Repository: microsoft/kiota (csharp)

Issue:
Missing typescript imports for createUntypedNodeFromDiscriminatorValue and UntypedNode
### What are you generating using Kiota, clients or plugins?

API Client/SDK

### In what context or format are you using Kiota?

Nuget tool

### Client library/SDK language

TypeScript

### Describe the bug

When I generate my typescript client with Kiota.Builder 1.14 (indirectly through FastEndpoints.ClientGen.Kiota), the resulting typescript files are missing the imports of  UntypedNode and createUntypedNodeFromDiscriminatorValue from @microsoft/kiota-abstractions.

Here is an example of a file 

``` Typescript
/* tslint:disable */
/* eslint-disable */
// Generated by Microsoft Kiota
// @ts-ignore
import { createDomainExceptionResponseFromDiscriminatorValue, createGetWishlistResponseFromDiscriminatorValue, serializeAddToWishlistRequest, serializeDeleteFromWishlistRequest, type AddToWishlistRequest, type DeleteFromWishlistRequest, type DomainExceptionResponse, type GetWishlistResponse } from '../../../../models/';
// @ts-ignore
import { type BaseRequestBuilder, type Parsable, type ParsableFactory, type RequestConfiguration, type RequestInformation, type RequestsMetadata } from '@microsoft/kiota-abstractions';

/**
 * Builds and executes requests for operations under /api/users/{userCodeOr-id}/wishlist
 */
export interface WishlistRequestBuilder extends BaseRequestBuilder<WishlistRequestBuilder> {
    /**
     * @param body The request body
     * @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
     * @returns {Promise<UntypedNode>}
     * @throws {DomainExceptionResponse} error when the service returns a 422 status code
     */
     delete(body: DeleteFromWishlistRequest, requestConfiguration?: RequestConfiguration<object> | undefined) : Promise<UntypedNode | undefined>;
    /**
     * @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
     * @returns {Promise<GetWishlistResponse>}
     * @throws {DomainExceptionResponse} error when the service returns a 422 status code
     */
     get(requestConfiguration?: RequestConfiguration<object> | undefined) : Promise<GetWishlistResponse | undefined>;
    /**
     * @param body The request body
     * @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
     * @returns {Promise<UntypedNode>}
     * @throws {DomainExceptionResponse} error when the service returns a 422 status code
     */
     post(body: AddToWishlistRequest, requestConfiguration?: RequestConfiguration<object> | undefined) : Promise<UntypedNode | undefined>;
    /**
     * @param body The request body
     * @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
     * @returns {RequestInformation}
     */
     toDeleteRequestInformation(body: DeleteFromWishlistRequest, requestConfiguration?: RequestConfiguration<object> | undefined) : RequestInformation;
    /**
     * @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
     * @returns {RequestInformation}
     */
     toGetRequestInformation(requestConfiguration?: RequestConfiguration<object> | undefined) : RequestInformation;
    /**
     * @param body The request body
     * @param requestConfiguration Configuration for the request such as headers, query parameters, and middleware options.
     * @returns {RequestInformation}
     */
     toPostRequestInformation(body: AddToWishlistRequest, requestConfiguration?: RequestConfiguration<object> | undefined) : RequestInformation;
}
/**
 * Uri template for the request builder.
 */
export const WishlistRequestBuilderUriTemplate = "{+baseurl}/api/users/{userCodeOr%2Did}/wishlist";
/**
 * Metadata for all the requests in the request builder.
 */
export const WishlistRequestBuilderRequestsMetadata: RequestsMetadata = {
    delete: {
        uriTemplate: WishlistRequestBuilderUriTemplate,
        responseBodyContentType: "text/plain;q=0.9",
        errorMappings: {
            422: createDomainExceptionResponseFromDiscriminatorValue as ParsableFactory<Parsable>,
        },
        adapterMethodName: "send",
        responseBodyFactory:  createUntypedNodeFromDiscriminatorValue,
        requestBodyContentType: "application/json",
        requestBodySerializer: serializeDeleteFromWishlistRequest,
        requestInformationContentSetMethod: "setContentFromParsable",
    },
    get: {
        uriTemplate: WishlistRequestBuilderUriTemplate,
        responseBodyContentType: "application/json",
        errorMappings: {
            422: createDomainExceptionResponseFromDiscriminatorValue as ParsableFactory<Parsable>,
        },
        adapterMethodName: "send",
        responseBodyFactory:  createGetWishlistResponseFromDiscriminatorValue,
    },
    post: {
        uriTemplate: WishlistRequestBuilderUriTemplate,
        responseBodyContentType: "text/plain;q=0.9",
        errorMappings: {
            422: createDomainExceptionResponseFromDiscriminatorValue as ParsableFactory<Parsable>,
        },
        adapterMethodName: "send",
        responseBodyFactory:  createUntypedNodeFromDiscriminatorValue,
        requestBodyContentType: "application/json",
        requestBodySerializer: serializeAddToWishlistRequest,
        requestInformationContentSetMethod: "setContentFromParsable",
    },
};
/* tslint:enable */
/* eslint-enable */
```


### Expected behavior

The import should include UntypedNode and createUntypedNodeFromDiscriminatorValue

### How to reproduce

Difficult to say which condition causes this

### Open API description file

_No response_

### Kiota Version

1.14

### Latest Kiota version known to work for scenario above?(Not required)

_No response_

### Known Workarounds

_No response_

### Configuration

_No response_

### Debug output

<details><summary>Click to expand log</summary>
```


<log output here>

```
</details>


### Other information

_No response_

Pull request:
Fixes https://github.com/microsoft/kiota/issues/4925

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2136947087..484ca91ea8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Ensures HashSet properties in `KiotaLock` maintain IgnoreCase comparer across runs [#4916](https://github.com/microsoft/kiota/issues/4916)
 - Dropped `client base url set to` message when generating plugins. [#4905](https://github.com/microsoft/kiota/issues/4905)
 - Emit `[GeneratedCode]` attribute for C# types. [#4907](https://github.com/microsoft/kiota/issues/4907)
+- Fixes missing imports for `UntypedNode` for method parameter and return value scenarios. [#4925](https://github.com/microsoft/kiota/issues/4925)
 
 ## [1.15.0] - 2024-06-06
 
diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
index 5e6c9673ca..92a5618a92 100644
--- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
+++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
@@ -528,7 +528,8 @@ private static bool HasMultipartBody(CodeMethod m) =>
             AbstractionsPackageName, true, "BackingStore", "BackedModel"),
         new (static x => x is CodeMethod m && HasMultipartBody(m),
             AbstractionsPackageName, MultipartBodyClassName, $"serialize{MultipartBodyClassName}"),
-        new (static x => x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Custom) && prop.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase),
+        new (static x => (x is CodeProperty prop && prop.IsOfKind(CodePropertyKind.Custom) && prop.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase))
+                         || (x is CodeMethod method && (method.Parameters.Any(param =>  param.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)) || method.ReturnType.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase))),
             AbstractionsPackageName, KiotaBuilder.UntypedNodeName, "createUntypedNodeFromDiscriminatorValue"),
     };
     private const string MultipartBodyClassName = "MultipartBody";


Test patch:
diff --git a/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs
index 0c7178dd7d..8da35ab461 100644
--- a/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs
+++ b/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs
@@ -840,5 +840,55 @@ public async Task AddsUsingForUntypedNode()
         Assert.Single(nodeUsing);
         Assert.Equal("@microsoft/kiota-abstractions", nodeUsing[0].Declaration.Name);
     }
+    [Fact]
+    public async Task AddsUsingForUntypedNodeInReturnType()
+    {
+        var requestBuilderClass = root.AddClass(new CodeClass() { Name = "NodeRequestBuilder" }).First();
+        var model = new CodeMethod
+        {
+            Name = "getAsync",
+            ReturnType = new CodeType
+            {
+                Name = KiotaBuilder.UntypedNodeName
+            }
+        };
+        requestBuilderClass.AddMethod(model);
+        await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.TypeScript }, root);
+        Assert.Equal(KiotaBuilder.UntypedNodeName, model.ReturnType.Name);// type is renamed
+        Assert.NotEmpty(requestBuilderClass.StartBlock.Usings);
+        var nodeUsing = requestBuilderClass.StartBlock.Usings.Where(static declaredUsing => declaredUsing.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)).ToArray();
+        Assert.Single(nodeUsing);
+        Assert.Equal("@microsoft/kiota-abstractions", nodeUsing[0].Declaration.Name);
+    }
+    [Fact]
+    public async Task AddsUsingForUntypedNodeInMethodParameter()
+    {
+        var requestBuilderClass = root.AddClass(new CodeClass() { Name = "NodeRequestBuilder" }).First();
+        var method = new CodeMethod
+        {
+            Name = "getAsync",
+            ReturnType = new CodeType
+            {
+                Name = "string",
+                IsExternal = true
+            }
+        };
+        method.AddParameter(new CodeParameter()
+        {
+            Name = "jsonData",
+            Type = new CodeType()
+            {
+                Name = KiotaBuilder.UntypedNodeName,
+                IsExternal = true
+            }
+        });
+        requestBuilderClass.AddMethod(method);
+        await ILanguageRefiner.Refine(new GenerationConfiguration { Language = GenerationLanguage.TypeScript }, root);
+        Assert.Equal(KiotaBuilder.UntypedNodeName, method.Parameters.First().Type.Name);// type is renamed
+        Assert.NotEmpty(requestBuilderClass.StartBlock.Usings);
+        var nodeUsing = requestBuilderClass.StartBlock.Usings.Where(static declaredUsing => declaredUsing.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)).ToArray();
+        Assert.Single(nodeUsing);
+        Assert.Equal("@microsoft/kiota-abstractions", nodeUsing[0].Declaration.Name);
+    }
     #endregion
 }