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

feature/request builders proxy #3938

Merged
merged 40 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
7009153
- adds missing documentation and deprecation information in typescrip…
baywet Dec 11, 2023
cfbebab
- draft TS request builders as interfaces
baywet Dec 11, 2023
f5a4438
- implements uri template constant
baywet Dec 12, 2023
b8b49f6
- adds a search depth limit to find by name
baywet Dec 12, 2023
e683c80
- implements navigation metadata generation
baywet Dec 12, 2023
2896b67
- fixes a bug where the file for the client request builder would hav…
baywet Dec 12, 2023
157af60
- adds base request builder for TS request builders
baywet Dec 12, 2023
b72b410
- marks imports as erasable
baywet Dec 12, 2023
15e7941
- fixes path parameters mapping
baywet Dec 12, 2023
0f682c0
- adds support for client constructor through proxy
baywet Dec 12, 2023
c047245
- fixes missing accept header value
baywet Dec 12, 2023
ec7c914
- typescript imports cleanup
baywet Dec 12, 2023
7bdaea2
- moves tests to the right location after typescript constants change
baywet Dec 15, 2023
96c48aa
- removes dead code in typescript generation
baywet Dec 15, 2023
801ec79
- fixes typescript property and refiner tests
baywet Dec 19, 2023
b6a063e
- code linting
baywet Dec 19, 2023
4ae477f
- fixes missing documentation and deprecation information on functions
baywet Dec 19, 2023
b087ec8
- moves async documentation tests to function
baywet Dec 19, 2023
1c44bba
- code linting
baywet Dec 19, 2023
46d3133
- moves return type test to functions
baywet Dec 19, 2023
c7d3a85
- restores default values functionality in typescript
baywet Dec 19, 2023
ccc443a
- fixe3s regression
baywet Dec 19, 2023
3702e17
- fixes factory unit tests
baywet Dec 20, 2023
b3c9d21
- fixes serialization methods unit tests
baywet Dec 20, 2023
a5d6369
- fixes constructor unit tests
baywet Dec 20, 2023
608741b
- fixes unit tests for navigation code constant
baywet Dec 20, 2023
6d4f17c
- fixes request generator and executor constant unit tests in typescript
baywet Dec 20, 2023
7ab6903
- formatting
baywet Dec 20, 2023
c3b782d
Apply suggestions from code review
baywet Jan 9, 2024
e572329
- code linting
baywet Jan 10, 2024
65af09c
- adds the ability for constants to have usings and documentation
baywet Jan 10, 2024
591dfdc
- avoids projecting unnecessary usings for navigation and request met…
baywet Jan 10, 2024
7450cae
- adds missing documentation for code constants
baywet Jan 10, 2024
7502995
- removes unecessary import of serialization methods in typescript
baywet Jan 11, 2024
04a0915
- code-linting: add constants to avoid multiple definitions
baywet Jan 11, 2024
3426ad7
- removes strings for typescript operation names
baywet Jan 12, 2024
98eae6c
- uses symbols for error mappings in typescript
baywet Jan 12, 2024
306a4cf
- adds changelog entry for typescript proxy generation
baywet Jan 19, 2024
8fc91f7
- changes client factory prefix to create
baywet Jan 19, 2024
070eb25
- removes unecessary import
baywet Jan 19, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Fixed a bug where scalar error mappings would be generated even though it's not supported by the http request adapter. [#4018](https://github.com/microsoft/kiota/issues/4018)
- Switched to proxy generation for TypeScript, leading to about ~44% bundle sizes reduction. [#3642](https://github.com/microsoft/kiota/issues/3642)

## [1.10.1] - 2024-01-12

Expand Down
10 changes: 7 additions & 3 deletions src/Kiota.Builder/CodeDOM/CodeBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ public IEnumerable<T> FindChildrenByName<T>(string childName) where T : ICodeEle
return Enumerable.Empty<T>();
}
public T? FindChildByName<T>(string childName, bool findInChildElements = true) where T : ICodeElement
{
return FindChildByName<T>(childName, findInChildElements ? uint.MaxValue : 1);
}
public T? FindChildByName<T>(string childName, uint maxDepth) where T : ICodeElement
{
ArgumentException.ThrowIfNullOrEmpty(childName);

Expand All @@ -165,10 +169,10 @@ public IEnumerable<T> FindChildrenByName<T>(string childName) where T : ICodeEle

if (InnerChildElements.TryGetValue(childName, out var result) && result is T castResult)
return castResult;
if (findInChildElements)
if (--maxDepth > 0)
andrueastman marked this conversation as resolved.
Show resolved Hide resolved
foreach (var childElement in InnerChildElements.Values.OfType<IBlock>())
{
var childResult = childElement.FindChildByName<T>(childName);
var childResult = childElement.FindChildByName<T>(childName, maxDepth);
if (childResult != null)
return childResult;
}
Expand Down Expand Up @@ -196,7 +200,7 @@ public void RemoveUsings(params CodeUsing[] codeUsings)
}
public void RemoveUsingsByDeclarationName(params string[] names)
{
if (names == null || names.Any(x => string.IsNullOrEmpty(x)))
if (names == null || names.Any(string.IsNullOrEmpty))
throw new ArgumentNullException(nameof(names));
var namesAsHashSet = names.ToHashSet(StringComparer.OrdinalIgnoreCase);
foreach (var usingToRemove in usings.Keys.Where(x => !string.IsNullOrEmpty(x.Declaration?.Name) && namesAsHashSet.Contains(x.Declaration!.Name)))
Expand Down
90 changes: 88 additions & 2 deletions src/Kiota.Builder/CodeDOM/CodeConstant.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,39 @@

namespace Kiota.Builder.CodeDOM;

public class CodeConstant : CodeTerminalWithKind<CodeConstantKind>
public class CodeConstant : CodeTerminalWithKind<CodeConstantKind>, IDocumentedElement
{
public BlockDeclaration StartBlock { get; set; } = new();
andrueastman marked this conversation as resolved.
Show resolved Hide resolved
public void AddUsing(params CodeUsing[] codeUsings) => StartBlock.AddUsings(codeUsings);
public CodeElement? OriginalCodeElement
{
get;
set;
}
#pragma warning disable CA1056 // URI-like properties should not be strings
public string? UriTemplate
{
get; init;
}
/// <inheritdoc/>
public CodeDocumentation Documentation
{
get; set;
} = new();
#pragma warning restore CA1056 // URI-like properties should not be strings
public static CodeConstant? FromQueryParametersMapping(CodeInterface source)
{
ArgumentNullException.ThrowIfNull(source);
if (source.Kind is not CodeInterfaceKind.QueryParameters) throw new InvalidOperationException("Cannot create a query parameters constant from a non query parameters interface");
if (!source.Properties.Any(static x => !string.IsNullOrEmpty(x.SerializationName))) return default;
return new CodeConstant
var result = new CodeConstant
{
Name = $"{source.Name.ToFirstCharacterLowerCase()}Mapper",
Kind = CodeConstantKind.QueryParametersMapper,
OriginalCodeElement = source,
};
result.Documentation.Description = "Mapper for query parameters from symbol name to serialization name represented as a constant.";
return result;
}
public static CodeConstant? FromCodeEnum(CodeEnum source)
{
Expand All @@ -33,9 +48,80 @@ public CodeElement? OriginalCodeElement
OriginalCodeElement = source,
};
}
internal const string UriTemplateSuffix = "UriTemplate";
internal const string RequestsMetadataSuffix = "RequestsMetadata";
internal const string NavigationMetadataSuffix = "NavigationMetadata";
public static CodeConstant? FromRequestBuilderClassToUriTemplate(CodeClass codeClass)
{
ArgumentNullException.ThrowIfNull(codeClass);
if (codeClass.Kind != CodeClassKind.RequestBuilder) return default;
if (codeClass.Properties.FirstOrDefaultOfKind(CodePropertyKind.UrlTemplate) is not CodeProperty urlTemplateProperty) throw new InvalidOperationException($"Couldn't find the url template property for class {codeClass.Name}");
var result = new CodeConstant
{
Name = $"{codeClass.Name.ToFirstCharacterLowerCase()}{UriTemplateSuffix}",
Kind = CodeConstantKind.UriTemplate,
UriTemplate = urlTemplateProperty.DefaultValue,
OriginalCodeElement = codeClass
};
baywet marked this conversation as resolved.
Show resolved Hide resolved
result.Documentation.Description = "Uri template for the request builder.";
return result;
}
public static CodeConstant? FromRequestBuilderToNavigationMetadata(CodeClass codeClass, CodeUsing[]? usingsToAdd = default)
{
ArgumentNullException.ThrowIfNull(codeClass);
if (codeClass.Kind != CodeClassKind.RequestBuilder) return default;
if (!(codeClass.Properties.Any(static x => x.Kind is CodePropertyKind.RequestBuilder) ||
codeClass.Methods.Any(static x => x.Kind is CodeMethodKind.IndexerBackwardCompatibility or CodeMethodKind.RequestBuilderWithParameters)))
return default;
var result = new CodeConstant
{
Name = $"{codeClass.Name.ToFirstCharacterLowerCase()}{NavigationMetadataSuffix}",
Kind = CodeConstantKind.NavigationMetadata,
OriginalCodeElement = codeClass,
};
result.Documentation.Description = "Metadata for all the navigation properties in the request builder.";
if (usingsToAdd is { Length: > 0 } usingsToAddList)
result.AddUsing(usingsToAddList);
return result;
}
public static CodeConstant? FromRequestBuilderToRequestsMetadata(CodeClass codeClass, CodeUsing[]? usingsToAdd = default)
{
ArgumentNullException.ThrowIfNull(codeClass);
if (codeClass.Kind != CodeClassKind.RequestBuilder) return default;
if (!codeClass.Methods.Any(static x => x.Kind is CodeMethodKind.RequestExecutor or CodeMethodKind.RequestGenerator))
return default;
var result = new CodeConstant
{
Name = $"{codeClass.Name.ToFirstCharacterLowerCase()}{RequestsMetadataSuffix}",
Kind = CodeConstantKind.RequestsMetadata,
OriginalCodeElement = codeClass,
};
result.Documentation.Description = "Metadata for all the requests in the request builder.";
if (usingsToAdd is { Length: > 0 } usingsToAddList)
result.AddUsing(usingsToAddList);
return result;
}
}
public enum CodeConstantKind
{
/// <summary>
/// Mapper for query parameters from symbol name to serialization name represented as a constant.
/// </summary>
QueryParametersMapper,
/// <summary>
/// Enum mapping keys represented as a constant.
/// </summary>
EnumObject,
/// <summary>
/// Uri template for the request builder.
/// </summary>
UriTemplate,
/// <summary>
/// Indexer methods, builders with parameters, and request builder properties represented as a single constant for proxy generation.
/// </summary>
NavigationMetadata,
/// <summary>
/// Request generators and executors represented as a single constant for proxy generation.
/// </summary>
RequestsMetadata,
}
1 change: 1 addition & 0 deletions src/Kiota.Builder/CodeDOM/CodeFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,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<CodeConstant> Constants => InnerChildElements.Values.OfType<CodeConstant>().OrderBy(static x => x.Name, StringComparer.Ordinal);

public IEnumerable<T> AddElements<T>(params T[] elements) where T : CodeElement
{
Expand Down
53 changes: 50 additions & 3 deletions src/Kiota.Builder/CodeDOM/CodeInterface.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,66 @@
namespace Kiota.Builder.CodeDOM;
using System;
using System.Linq;

namespace Kiota.Builder.CodeDOM;

public enum CodeInterfaceKind
{
Custom,
Model,
QueryParameters,
RequestConfiguration
RequestBuilder,
}

public class CodeInterface : ProprietableBlock<CodeInterfaceKind, InterfaceDeclaration>, ITypeDefinition
public class CodeInterface : ProprietableBlock<CodeInterfaceKind, InterfaceDeclaration>, ITypeDefinition, IDeprecableElement
{
public CodeClass? OriginalClass
{
get; set;
}
public DeprecationInformation? Deprecation
{
get; set;
}

public static CodeInterface FromRequestBuilder(CodeClass codeClass, CodeUsing[]? usingsToAdd = default)
{
ArgumentNullException.ThrowIfNull(codeClass);
if (codeClass.Kind != CodeClassKind.RequestBuilder) throw new InvalidOperationException($"Cannot create a request builder interface from a non request builder class");
var result = new CodeInterface
{
Name = codeClass.Name,
Kind = CodeInterfaceKind.RequestBuilder,
OriginalClass = codeClass,
Documentation = codeClass.Documentation,
Deprecation = codeClass.Deprecation,
};

if (codeClass.Methods
.Where(static x => x.Kind is CodeMethodKind.RequestGenerator or
CodeMethodKind.RequestExecutor or
CodeMethodKind.IndexerBackwardCompatibility or
CodeMethodKind.RequestBuilderWithParameters)
.Select(static x => (CodeMethod)x.Clone()).ToArray() is { Length: > 0 } methods)
result.AddMethod(methods);
if (codeClass.Properties
.Where(static x => x.Kind is CodePropertyKind.RequestBuilder)
.Select(static x => (CodeProperty)x.Clone()).ToArray() is { Length: > 0 } properties)
result.AddProperty(properties);

if (codeClass.Usings.ToArray() is { Length: > 0 } usings)
{
foreach (var usingToCopy in usings.Where(static x => x.Declaration?.TypeDefinition is CodeInterface or CodeClass { Kind: CodeClassKind.RequestBuilder }))
{
usingToCopy.IsErasable = true;
}
result.AddUsing(usings);
}
if (usingsToAdd is { Length: > 0 } usingsToAddList)
result.AddUsing(usingsToAddList);
if (codeClass.StartBlock.Inherits is not null)
result.StartBlock.AddImplements(codeClass.StartBlock.Inherits);
return result;
}
}
public class InterfaceDeclaration : ProprietableBlockDeclaration
{
Expand Down
1 change: 1 addition & 0 deletions src/Kiota.Builder/CodeDOM/IBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Kiota.Builder.CodeDOM;
public interface IBlock
{
T? FindChildByName<T>(string childName, bool findInChildElements = true) where T : ICodeElement;
T? FindChildByName<T>(string childName, uint maxDepth) where T : ICodeElement;
IEnumerable<T> FindChildrenByName<T>(string childName) where T : ICodeElement;
void AddUsing(params CodeUsing[] codeUsings);
CodeElement? Parent
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,5 +280,5 @@ public static string CleanupXMLString(this string? original)
/// <param name="b">The second string</param>
/// <returns></returns>
public static bool EqualsIgnoreCase(this string? a, string? b)
=> String.Equals(a, b, StringComparison.OrdinalIgnoreCase);
=> string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public override string NormalizeFileName(CodeElement currentElement)
CodeFile currentFile when modelsNamespace is not null &&
currentElement.GetImmediateParentOfType<CodeNamespace>() is CodeNamespace currentNamespace &&
!(modelsNamespace.IsParentOf(currentNamespace) || modelsNamespace == currentNamespace) &&
!currentFile.Classes.Any(static x => x.Kind is CodeClassKind.RequestBuilder && x.Methods.Any(static y => y.Kind is CodeMethodKind.ClientConstructor))
!currentFile.Interfaces.Any(static x => x.Kind is CodeInterfaceKind.RequestBuilder && x.OriginalClass is not null && x.OriginalClass.Methods.Any(static y => y.Kind is CodeMethodKind.ClientConstructor))
=> IndexFileName,
_ => GetDefaultFileName(currentElement),
};
Expand Down
Loading
Loading