From c427e484f10f3166b78400785c1ac82098f42edc Mon Sep 17 00:00:00 2001 From: Chenjie Shi Date: Fri, 21 Jun 2024 03:10:02 +0800 Subject: [PATCH] [tcgc] only expose top level client in SdkPackage (#1033) resolve: https://github.com/Azure/typespec-azure/issues/1040 --- .../client_hierarchy-2024-5-18-18-19-30.md | 7 +++ .../src/interfaces.ts | 1 - .../src/package.ts | 7 +-- .../test/decorators.test.ts | 13 ++++- .../test/package.test.ts | 55 ++++++++++++------- .../test/types/multipart-types.test.ts | 7 ++- 6 files changed, 58 insertions(+), 32 deletions(-) create mode 100644 .chronus/changes/client_hierarchy-2024-5-18-18-19-30.md diff --git a/.chronus/changes/client_hierarchy-2024-5-18-18-19-30.md b/.chronus/changes/client_hierarchy-2024-5-18-18-19-30.md new file mode 100644 index 0000000000..e0e79f7795 --- /dev/null +++ b/.chronus/changes/client_hierarchy-2024-5-18-18-19-30.md @@ -0,0 +1,7 @@ +--- +changeKind: breaking +packages: + - "@azure-tools/typespec-client-generator-core" +--- + +only expose top level client in `SdkPackage` \ No newline at end of file diff --git a/packages/typespec-client-generator-core/src/interfaces.ts b/packages/typespec-client-generator-core/src/interfaces.ts index d881004582..d3fa82fb26 100644 --- a/packages/typespec-client-generator-core/src/interfaces.ts +++ b/packages/typespec-client-generator-core/src/interfaces.ts @@ -26,7 +26,6 @@ export interface SdkContext< > extends TCGCContext { emitContext: EmitContext; experimental_sdkPackage: SdkPackage; - __clients?: SdkClientType[]; } export interface SdkEmitterOptions { diff --git a/packages/typespec-client-generator-core/src/package.ts b/packages/typespec-client-generator-core/src/package.ts index 899a968724..1813422ca2 100644 --- a/packages/typespec-client-generator-core/src/package.ts +++ b/packages/typespec-client-generator-core/src/package.ts @@ -573,7 +573,6 @@ function createSdkClientType< // eslint-disable-next-line deprecation/deprecation arm: client.kind === "SdkClient" ? client.arm : false, }; - context.__clients!.push(sdkClientType); return diagnostics.wrap(sdkClientType); } @@ -613,17 +612,13 @@ export function getSdkPackage< TServiceOperation extends SdkServiceOperation, >(context: SdkContext): SdkPackage { const diagnostics = createDiagnosticCollector(); - context.__clients = new Array>(); populateApiVersionInformation(context); const modelsAndEnums = diagnostics.pipe(getAllModelsWithDiagnostics(context)); - for (const client of listClients(context)) { - createSdkClientType(context, client); - } const crossLanguagePackageId = diagnostics.pipe(getCrossLanguagePackageId(context)); return { name: getClientNamespaceString(context)!, rootNamespace: getClientNamespaceString(context)!, - clients: Array.from(context.__clients.values()), + clients: listClients(context).map((c) => diagnostics.pipe(createSdkClientType(context, c))), models: modelsAndEnums.filter((x): x is SdkModelType => x.kind === "model"), enums: modelsAndEnums.filter((x): x is SdkEnumType => x.kind === "enum"), diagnostics: diagnostics.diagnostics, diff --git a/packages/typespec-client-generator-core/test/decorators.test.ts b/packages/typespec-client-generator-core/test/decorators.test.ts index 9ebc95ff40..c9a55d64da 100644 --- a/packages/typespec-client-generator-core/test/decorators.test.ts +++ b/packages/typespec-client-generator-core/test/decorators.test.ts @@ -21,7 +21,13 @@ import { shouldGenerateConvenient, shouldGenerateProtocol, } from "../src/decorators.js"; -import { SdkMethodResponse, SdkOperationGroup, UsageFlags } from "../src/interfaces.js"; +import { + SdkClientType, + SdkHttpOperation, + SdkMethodResponse, + SdkOperationGroup, + UsageFlags, +} from "../src/interfaces.js"; import { getCrossLanguageDefinitionId, getCrossLanguagePackageId } from "../src/public-utils.js"; import { getAllModels } from "../src/types.js"; import { SdkTestRunner, createSdkContextTestHelper, createSdkTestRunner } from "./test-host.js"; @@ -3284,7 +3290,7 @@ describe("typespec-client-generator-core: decorators", () => { ` ); const sdkPackage = runner.context.experimental_sdkPackage; - strictEqual(sdkPackage.clients.length, 2); + strictEqual(sdkPackage.clients.length, 1); const versioningClient = sdkPackage.clients.find((x) => x.name === "VersioningClient"); ok(versioningClient); strictEqual(versioningClient.methods.length, 2); @@ -3306,7 +3312,8 @@ describe("typespec-client-generator-core: decorators", () => { strictEqual(clientAccessor.name, "getInterfaceV2"); deepStrictEqual(clientAccessor.apiVersions, ["v2"]); - const interfaceV2 = sdkPackage.clients.find((x) => x.name === "InterfaceV2"); + const interfaceV2 = versioningClient.methods.find((x) => x.kind === "clientaccessor") + ?.response as SdkClientType; ok(interfaceV2); strictEqual(interfaceV2.methods.length, 1); diff --git a/packages/typespec-client-generator-core/test/package.test.ts b/packages/typespec-client-generator-core/test/package.test.ts index b9ec33b86b..fcdff655f0 100644 --- a/packages/typespec-client-generator-core/test/package.test.ts +++ b/packages/typespec-client-generator-core/test/package.test.ts @@ -4,6 +4,7 @@ import { ApiKeyAuth, OAuth2Flow, Oauth2Auth } from "@typespec/http"; import { deepStrictEqual, ok, strictEqual } from "assert"; import { beforeEach, describe, it } from "vitest"; import { + SdkClientType, SdkCredentialParameter, SdkCredentialType, SdkEndpointParameter, @@ -577,10 +578,11 @@ describe("typespec-client-generator-core: package", () => { } `); const sdkPackage = runner.context.experimental_sdkPackage; - strictEqual(sdkPackage.clients.length, 2); + strictEqual(sdkPackage.clients.length, 1); const mainClient = sdkPackage.clients.find((c) => c.name === "TestServiceClient"); - const operationGroup = sdkPackage.clients.find((c) => c.name === "MyOperationGroup"); + const operationGroup = mainClient?.methods.find((c) => c.kind === "clientaccessor") + ?.response as SdkClientType; ok(mainClient && operationGroup); strictEqual(mainClient.methods.length, 1); @@ -620,12 +622,17 @@ describe("typespec-client-generator-core: package", () => { } `); const sdkPackage = runner.context.experimental_sdkPackage; - strictEqual(sdkPackage.clients.length, 4); + strictEqual(sdkPackage.clients.length, 1); - const mainClient = sdkPackage.clients.find((c) => c.name === "TestServiceClient"); - const fooClient = sdkPackage.clients.find((c) => c.name === "Foo"); - const fooBarClient = sdkPackage.clients.filter((c) => c.name === "Bar")![0]; - const barClient = sdkPackage.clients.filter((c) => c.name === "Bar")![1]; + const mainClient = sdkPackage.clients[0]; + const fooClient = mainClient.methods.find( + (m) => m.kind === "clientaccessor" && m.name === "getFoo" + )?.response as SdkClientType; + const fooBarClient = fooClient.methods.find((m) => m.kind === "clientaccessor") + ?.response as SdkClientType; + const barClient = mainClient.methods.find( + (m) => m.kind === "clientaccessor" && m.name === "getBar" + )?.response as SdkClientType; ok(mainClient && fooClient && fooBarClient && barClient); strictEqual(mainClient.methods.length, 2); @@ -2449,12 +2456,11 @@ describe("typespec-client-generator-core: package", () => { ` ); const sdkPackage = runnerWithCore.context.experimental_sdkPackage; - strictEqual(sdkPackage.clients.length, 2); - const client = sdkPackage.clients.find((c) => c.initialization.access === "internal"); + strictEqual(sdkPackage.clients.length, 1); + const parentClient = sdkPackage.clients[0]; + const client = parentClient.methods.find((x) => x.kind === "clientaccessor") + ?.response as SdkClientType; ok(client); - const parentClient = sdkPackage.clients.filter( - (c) => c.initialization.access === "public" - )[0]; strictEqual(client.methods.length, 2); // TEST GET STATUS @@ -2671,10 +2677,11 @@ describe("typespec-client-generator-core: package", () => { ` ); const sdkPackage = runnerWithCore.context.experimental_sdkPackage; - strictEqual(sdkPackage.clients.length, 2); + strictEqual(sdkPackage.clients.length, 1); strictEqual(sdkPackage.models.length, 1); strictEqual(sdkPackage.models[0].name, "Manufacturer"); - const widgetClient = sdkPackage.clients.find((c) => c.name === "Widgets"); + const widgetClient = sdkPackage.clients[0].methods.find((x) => x.kind === "clientaccessor") + ?.response as SdkClientType; ok(widgetClient); strictEqual(widgetClient.initialization.properties.length, 3); strictEqual(widgetClient.initialization.access, "internal"); @@ -2953,7 +2960,9 @@ describe("typespec-client-generator-core: package", () => { sdkPackage.models.map((x) => x.name).sort(), ["CheckupCollectionWithNextLink", "Checkup", "PetStoreError", "CheckupUpdate"].sort() ); - const createOrUpdate = sdkPackage.clients[0].methods[0]; + const client = sdkPackage.clients[0].methods.find((x) => x.kind === "clientaccessor") + ?.response as SdkClientType; + const createOrUpdate = client.methods[0]; strictEqual(createOrUpdate.kind, "basic"); strictEqual(createOrUpdate.name, "createOrUpdate"); strictEqual(createOrUpdate.parameters.length, 5); @@ -3048,7 +3057,10 @@ describe("typespec-client-generator-core: package", () => { const sdkPackage = runnerWithCore.context.experimental_sdkPackage; strictEqual(sdkPackage.models.length, 2); - const createOrReplace = sdkPackage.clients[0].methods[1]; + const client = sdkPackage.clients[0].methods.find((x) => x.kind === "clientaccessor") + ?.response as SdkClientType; + + const createOrReplace = client.methods[1]; strictEqual(createOrReplace.kind, "basic"); strictEqual(createOrReplace.name, "createOrReplaceDataConnection"); strictEqual(createOrReplace.parameters.length, 5); @@ -3215,7 +3227,9 @@ describe("typespec-client-generator-core: package", () => { `); const sdkPackage = runner.context.experimental_sdkPackage; - strictEqual(sdkPackage.clients[0].methods[0].parameters[0].clientDefaultValue, "v2"); + const client = sdkPackage.clients[0].methods.find((x) => x.kind === "clientaccessor") + ?.response as SdkClientType; + strictEqual(client.methods[0].parameters[0].clientDefaultValue, "v2"); }); it("default api version for operation is", async () => { @@ -3350,9 +3364,10 @@ function getServiceMethodOfClient( numMethods: number = 1, methodIndex: number = 0 ): SdkServiceMethod { - let client = sdkPackage.clients.filter((c) => c.initialization.access === "internal")[0]; - if (!client) { - client = sdkPackage.clients.filter((c) => c.initialization.access === "public")[0]; + let client = sdkPackage.clients[0]; + if (client.methods.some((x) => x.kind === "clientaccessor")) { + client = client.methods.find((x) => x.kind === "clientaccessor") + ?.response as SdkClientType; } strictEqual(client.methods.length, numMethods); const method = client.methods[methodIndex]; diff --git a/packages/typespec-client-generator-core/test/types/multipart-types.test.ts b/packages/typespec-client-generator-core/test/types/multipart-types.test.ts index f4734e744f..cd6ea53e17 100644 --- a/packages/typespec-client-generator-core/test/types/multipart-types.test.ts +++ b/packages/typespec-client-generator-core/test/types/multipart-types.test.ts @@ -2,7 +2,7 @@ import { expectDiagnostics } from "@typespec/compiler/testing"; import { ok, strictEqual } from "assert"; import { beforeEach, describe, it } from "vitest"; -import { UsageFlags } from "../../src/interfaces.js"; +import { SdkClientType, SdkHttpOperation, UsageFlags } from "../../src/interfaces.js"; import { getAllModelsWithDiagnostics } from "../../src/types.js"; import { SdkTestRunner, createSdkTestRunner } from "../test-host.js"; @@ -208,7 +208,10 @@ describe("typespec-client-generator-core: multipart types", () => { upload(...WidgetForm): Widget; } `); - const formDataMethod = runner.context.experimental_sdkPackage.clients[0].methods[0]; + const client = runner.context.experimental_sdkPackage.clients[0].methods.find( + (x) => x.kind === "clientaccessor" + )?.response as SdkClientType; + const formDataMethod = client.methods[0]; strictEqual(formDataMethod.kind, "basic"); strictEqual(formDataMethod.name, "upload"); strictEqual(formDataMethod.parameters.length, 3);