Skip to content

Commit 183f085

Browse files
feat: input type updates for multiservice support (#9399)
This PR adds emitter updates and fixes in preparation for generating multiservice clients. contributes to: #9032
1 parent 650da53 commit 183f085

File tree

85 files changed

+1228
-331
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+1228
-331
lines changed

packages/http-client-csharp/emitter/src/lib/client-converter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
getParameterDefaultValue,
2525
} from "./operation-converter.js";
2626
import { fromSdkType } from "./type-converter.js";
27-
import { isReadOnly } from "./utils.js";
27+
import { isMultiServiceClient, isReadOnly } from "./utils.js";
2828

2929
type SdkClientType = SdkClientTypeOfT<SdkHttpOperation>;
3030

@@ -79,6 +79,7 @@ function fromSdkClient(
7979
apiVersions: client.apiVersions,
8080
parent: undefined,
8181
children: undefined,
82+
isMultiServiceClient: isMultiServiceClient(client),
8283
};
8384

8485
sdkContext.__typeCache.updateSdkClientReferences(client, inputClient);

packages/http-client-csharp/emitter/src/lib/client-model-builder.ts

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,24 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4-
import { UsageFlags } from "@azure-tools/typespec-client-generator-core";
4+
import {
5+
SdkClientType,
6+
SdkEnumType,
7+
SdkHttpOperation,
8+
UsageFlags,
9+
} from "@azure-tools/typespec-client-generator-core";
510
import { CSharpEmitterContext } from "../sdk-context.js";
611
import { CodeModel } from "../type/code-model.js";
712
import { InputEnumType, InputLiteralType, InputModelType } from "../type/input-type.js";
813
import { fromSdkClients } from "./client-converter.js";
914
import { fromSdkNamespaces } from "./namespace-converter.js";
1015
import { processServiceAuthentication } from "./service-authentication.js";
1116
import { fromSdkType } from "./type-converter.js";
12-
import { firstLetterToUpperCase, getClientNamespaceString } from "./utils.js";
17+
import {
18+
containsMultiServiceClient,
19+
firstLetterToUpperCase,
20+
getClientNamespaceString,
21+
} from "./utils.js";
1322

1423
/**
1524
* Creates the code model from the SDK context.
@@ -31,13 +40,8 @@ export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
3140
types.filter((type) => type.kind === "enum") as InputEnumType[],
3241
];
3342

34-
const sdkApiVersionEnums = sdkPackage.enums.filter((e) => e.usage === UsageFlags.ApiVersionEnum);
3543
const rootClients = sdkPackage.clients;
36-
const rootApiVersions =
37-
sdkApiVersionEnums.length > 0
38-
? sdkApiVersionEnums[0].values.map((v) => v.value as string).flat()
39-
: (rootClients[0]?.apiVersions ?? []);
40-
44+
const rootApiVersions = parseApiVersions(sdkPackage.enums, rootClients);
4145
const inputClients = fromSdkClients(sdkContext, rootClients, rootApiVersions);
4246

4347
// TODO -- TCGC now does not have constants field in its sdkPackage, they might add it in the future.
@@ -61,6 +65,30 @@ export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
6165
return clientModel;
6266
}
6367

68+
/**
69+
* Parses and returns the correct API versions for the library.
70+
* Handles both regular and multiservice client libraries.
71+
*
72+
* @param enums - Array of enums from the SDK package
73+
* @param rootClients - Array of root clients from the SDK package
74+
* @returns Array of API version strings
75+
*/
76+
function parseApiVersions(
77+
enums: SdkEnumType[],
78+
rootClients: SdkClientType<SdkHttpOperation>[],
79+
): string[] {
80+
if (containsMultiServiceClient(rootClients)) {
81+
return rootClients[0]?.apiVersions ?? [];
82+
}
83+
84+
const apiVersionEnum = enums.find((e) => (e.usage & UsageFlags.ApiVersionEnum) !== 0);
85+
if (apiVersionEnum) {
86+
return apiVersionEnum.values.map((v) => v.value as string);
87+
}
88+
89+
return rootClients[0]?.apiVersions ?? [];
90+
}
91+
6492
/**
6593
* Fixes naming conflicts for constants, enums, and models.
6694
*

packages/http-client-csharp/emitter/src/lib/utils.ts

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import {
22
listAllServiceNamespaces,
3+
SdkClientType,
4+
SdkHttpOperation,
35
SdkHttpParameter,
46
SdkMethodParameter,
57
SdkModelPropertyType,
@@ -139,10 +141,19 @@ export async function execAsync(
139141
}
140142

141143
export function getClientNamespaceString(context: CSharpEmitterContext): string | undefined {
142-
return getClientNamespaceStringHelper(
143-
context.emitContext.options["package-name"],
144-
listAllServiceNamespaces(context)[0],
145-
);
144+
const packageName = context.emitContext.options["package-name"];
145+
const serviceNamespaces = listAllServiceNamespaces(context);
146+
const firstNamespace = serviceNamespaces.length > 0 ? serviceNamespaces[0] : undefined;
147+
148+
if (packageName) {
149+
return getClientNamespaceStringHelper(packageName, firstNamespace);
150+
}
151+
152+
if (containsMultiServiceClient(context.sdkPackage.clients)) {
153+
return getClientNamespaceStringHelper(context.sdkPackage.clients[0].namespace);
154+
}
155+
156+
return getClientNamespaceStringHelper(undefined, firstNamespace);
146157
}
147158

148159
export function getClientNamespaceStringHelper(
@@ -186,3 +197,33 @@ export function isReadOnly(
186197
return false;
187198
}
188199
}
200+
201+
/**
202+
* Determines if the library contains a multiservice client.
203+
*
204+
* @param rootClients - Array of root clients from the SDK package
205+
* @returns True if this is a multiservice client library, false otherwise
206+
* @beta
207+
*/
208+
export function containsMultiServiceClient(
209+
rootClients: SdkClientType<SdkHttpOperation>[],
210+
): boolean {
211+
if (rootClients.length === 0) {
212+
return false;
213+
}
214+
215+
return isMultiServiceClient(rootClients[0]);
216+
}
217+
218+
/**
219+
* Determines if a client is a multiservice client.
220+
* A multiservice client is one where the underlying service is an array of services
221+
* with more than one element.
222+
*
223+
* @param client - The SDK client to check
224+
* @returns True if this is a multiservice client, false otherwise
225+
* @beta
226+
*/
227+
export function isMultiServiceClient(client: SdkClientType<SdkHttpOperation>): boolean {
228+
return Array.isArray(client.__raw.service) && client.__raw.service.length > 1;
229+
}

packages/http-client-csharp/emitter/src/type/input-type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export interface InputClient extends DecoratedType {
4343
crossLanguageDefinitionId: string;
4444
parent?: InputClient;
4545
children?: InputClient[];
46+
isMultiServiceClient: boolean;
4647
}
4748

4849
/**

0 commit comments

Comments
 (0)