diff --git a/.chronus/changes/nested-test-cases-for-clientinit-2026-0-20-9-55-29.md b/.chronus/changes/nested-test-cases-for-clientinit-2026-0-20-9-55-29.md new file mode 100644 index 0000000000..716f22d8a6 --- /dev/null +++ b/.chronus/changes/nested-test-cases-for-clientinit-2026-0-20-9-55-29.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@azure-tools/azure-http-specs" +--- + +add nested test cases for client-initialization diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/client.tsp b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/default/main.tsp similarity index 50% rename from packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/client.tsp rename to packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/default/main.tsp index 6859e31088..ff9b68819c 100644 --- a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/client.tsp +++ b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/default/main.tsp @@ -1,23 +1,19 @@ -import "./main.tsp"; -import "@azure-tools/typespec-client-generator-core"; -import "@typespec/spector"; import "@typespec/http"; +import "@typespec/spector"; +import "@azure-tools/typespec-client-generator-core"; -using Spector; using Http; +using Spector; +using Azure.ClientGenerator.Core; -@route("/azure/client-generator-core/client-initialization") -namespace _Specs_.Azure.ClientGenerator.Core.ClientInitialization; +@doc("Test for client initialization decorator - moving parameters from method to client level") +@scenarioService("/azure/client-generator-core/client-initialization/default") +namespace _Specs_.Azure.ClientGenerator.Core.ClientInitialization.DefaultClient; -@@global.Azure.ClientGenerator.Core.clientNamespace(_Specs_.Azure.ClientGenerator.Core.ClientInitialization, - "azure.clientgenerator.core.clientinitialization", - "java" -); -@@global.Azure.ClientGenerator.Core.clientNamespace(Service, - "azure.clientgenerator.core.clientinitialization", +@global.Azure.ClientGenerator.Core.clientNamespace( + "azure.clientgenerator.core.clientinitialization.defaultclient", "java" -); - +) model HeaderParamClientOptions { @doc("The name of the client. This parameter is used as a header in all operations.") name: string; @@ -47,6 +43,32 @@ model ParamAliasClientOptions { blobName: string; } +model BlobQueryParamClientOptions { + @doc("The blob name to use for operations") + blobName: string; +} + +// Common parameter types and models + +model NameHeaderParam { + @header("name") + name: string; +} + +model RegionQueryParam { + @query + region: string; +} + +model Input { + name: string; +} + +model BlobQueryParam { + @query + blobName: string; +} + // Scenario 1: Header parameter moved to client level @scenarioDoc(""" Client for testing header parameter moved to client level. @@ -68,13 +90,17 @@ model ParamAliasClientOptions { @doc("Client for testing header parameter moved to client level.") @global.Azure.ClientGenerator.Core.client({ name: "HeaderParamClient", - service: Service, }) @global.Azure.ClientGenerator.Core.clientInitialization(HeaderParamClientOptions) @route("/header-param") interface HeaderParam { - withQuery is Service.HeaderParam.withQuery; - withBody is Service.HeaderParam.withBody; + @route("/with-query") + @get + withQuery(...NameHeaderParam, @query id: string): void; + + @route("/with-body") + @post + withBody(...NameHeaderParam, @body body: Input): void; } // Scenario 2: Multiple parameters (header and query) moved to client level @@ -97,47 +123,63 @@ interface HeaderParam { ``` """) @scenario +@doc("Client for testing multiple parameters (header and query) moved to client level.") @global.Azure.ClientGenerator.Core.client({ name: "MultipleParamsClient", - service: Service, }) @global.Azure.ClientGenerator.Core.clientInitialization(MultipleParamsClientOptions) @route("/multiple-params") interface MultipleParams { - withQuery is Service.MultipleParams.withQuery; - withBody is Service.MultipleParams.withBody; + @route("/with-query") + @get + withQuery(...NameHeaderParam, ...RegionQueryParam, @query id: string): void; + + @route("/with-body") + @post + withBody(...NameHeaderParam, ...RegionQueryParam, @body body: Input): void; } // Scenario 3: Mix of client-level and method-level parameters @scenarioDoc(""" - Client for testing a mix of client-level and method-level parameters. - - Parameters elevated to client level: - - name: "test-name-value" (header parameter) - - Parameters remaining at method level: - - region: "us-west" (query parameter) - - Expected client usage: - ```ts - const client = new MixedParamsClient({ - name: "test-name-value" - }); - - client.withQuery(region: "us-west", id: "test-id"); // region stays as method param - client.withBody( region: "us-west", body: { name: "test-name" }); // region stays as method param - ``` + Client for testing a mix of client-level and method-level parameters. + + Parameters elevated to client level: + - name: "test-name-value" (header parameter) + + Parameters remaining at method level: + - region: "us-west" (query parameter) + + Expected client usage: + ```ts + const client = new MixedParamsClient({ + name: "test-name-value" + }); + + client.withQuery(region: "us-west", id: "test-id"); // region stays as method param + client.withBody(region: "us-west", body: { name: "test-name" }); // region stays as method param + ``` """) @scenario +@doc("Client for testing a mix of client-level and method-level parameters.") @global.Azure.ClientGenerator.Core.client({ name: "MixedParamsClient", - service: Service, }) @global.Azure.ClientGenerator.Core.clientInitialization(MixedParamsClientOptions) @route("/mixed-params") interface MixedParams { - withQuery is Service.MixedParams.withQuery; - withBody is Service.MixedParams.withBody; + @route("/with-query") + @get + withQuery(...NameHeaderParam, ...RegionQueryParam, @query id: string): void; + + @route("/with-body") + @post + withBody( + ...NameHeaderParam, + ...RegionQueryParam, + @body body: { + name: string; + }, + ): void; } // Scenario 4: Path parameter moved to client level @@ -160,16 +202,24 @@ interface MixedParams { ``` """) @scenario +@doc("Blob operations with path parameter that should be moved to client level") @global.Azure.ClientGenerator.Core.client({ name: "PathParamClient", - service: Service, }) @global.Azure.ClientGenerator.Core.clientInitialization(PathParamClientOptions) @route("/path") interface PathParam { - withQuery is Service.PathParam.withQuery; - getStandalone is Service.PathParam.getStandalone; - deleteStandalone is Service.PathParam.deleteStandalone; + @route("/{blobName}/with-query") + @get + withQuery(@path blobName: string, @query format?: string): void; + + @route("/{blobName}/get-standalone") + @get + getStandalone(@path blobName: string): BlobProperties; + + @route("/{blobName}") + @delete + deleteStandalone(@path blobName: string): void; } // Scenario 5: Parameter aliases for better client API names @@ -177,70 +227,86 @@ interface PathParam { Client for testing the @paramAlias decorator for renaming parameters in client code. Parameters elevated to client level: - - blobName: "sample-blob" (path parameter) + - blobName: "sample-blob" (path parameter with @paramAlias("blob")) Expected client usage: ```ts - // Elevated to client level via alias - client.withAliasedName(); + const client = new ParamAliasClient({ + blobName: "sample-blob" + }); - // Elevated to client level via original name + // Operations don't need blob/blobName parameter + client.withAliasedName(); client.withOriginalName(); ``` """) @scenario -@global.Azure.ClientGenerator.Core.clientInitialization(ParamAliasClientOptions) +@doc("Operations demonstrating the @paramAlias decorator for renaming parameters in client code") @global.Azure.ClientGenerator.Core.client({ name: "ParamAliasClient", - service: Service, }) +@global.Azure.ClientGenerator.Core.clientInitialization(ParamAliasClientOptions) @route("/param-alias") interface ParamAlias { - withAliasedName is Service.ParamAlias.withAliasedName; - withOriginalName is Service.ParamAlias.withOriginalName; + @route("/{blob}/with-aliased-name") + @get + withAliasedName( + @path + blob: string, + ): void; + + @route("/{blobName}/with-original-name") + @get + withOriginalName( + @path + blobName: string, + ): void; } +@doc("Properties of a blob") +model BlobProperties { + name: string; + size: int64; + contentType: string; + createdOn: utcDateTime; +} + +// Scenario 6: Query parameter moved to client level +@scenarioDoc(""" + Client for testing query parameter moved to client level. + + Parameters elevated to client level: + - blobName: "test-blob" (query parameter) + + Expected client usage: + ```ts + const client = new QueryParamClient({ + blobName: "test-blob" + }); + + // Operations don't need blobName parameter + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Blob operations with query parameter that should be moved to client level") @global.Azure.ClientGenerator.Core.client({ - name: "ParentClient", - service: Service, + name: "QueryParamClient", }) -namespace ParentClient { - @scenarioDoc(""" - Client for testing a path parameter (blobName) moved to client level, in child client. - - The child client can be initialized individually, or via its parent client. - - Parameters elevated to client level: - - blobName: "sample-blob" (path parameter) - - Expected client usage: - ```ts - // via ParentClient - const client = new ParentClient.getChildClient({ - blobName: "sample-blob" - }); - - // directly - const client = new ChildClient({ - blobName: "sample-blob" - }); - - // No need to pass blobName to any operations - client.withQuery(format: "text"); - client.getStandalone(); - client.deleteStandalone(); - ``` - """) - @scenario - @global.Azure.ClientGenerator.Core.operationGroup - @global.Azure.ClientGenerator.Core.clientInitialization({ - parameters: PathParamClientOptions, - initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually | global.Azure.ClientGenerator.Core.InitializedBy.parent, - }) - @route("/child-client") - interface ChildClient { - withQuery is Service.ChildClient.withQuery; - getStandalone is Service.ChildClient.getStandalone; - deleteStandalone is Service.ChildClient.deleteStandalone; - } +@global.Azure.ClientGenerator.Core.clientInitialization(BlobQueryParamClientOptions) +@route("/query") +interface QueryParam { + @route("/with-query") + @get + withQuery(...BlobQueryParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...BlobQueryParam): BlobProperties; + + @route("/delete-resource") + @delete + deleteStandalone(...BlobQueryParam): void; } diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/default/mockapi.ts b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/default/mockapi.ts new file mode 100644 index 0000000000..7d7c1d35b1 --- /dev/null +++ b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/default/mockapi.ts @@ -0,0 +1,237 @@ +import { json, passOnSuccess, ScenarioMockApi } from "@typespec/spec-api"; + +export const Scenarios: Record = {}; + +// Mock responses for HeaderParam scenario +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_DefaultClient_HeaderParam = passOnSuccess( + [ + { + uri: "/azure/client-generator-core/client-initialization/default/header-param/with-query", + method: "get", + request: { + query: { + id: "test-id", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/default/header-param/with-body", + method: "post", + request: { + headers: { + name: "test-name-value", + }, + body: json({ + name: "test-name", + }), + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ], +); + +// Mock responses for MultipleParams scenario +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_DefaultClient_MultipleParams = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/default/multiple-params/with-query", + method: "get", + request: { + query: { + id: "test-id", + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/default/multiple-params/with-body", + method: "post", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + body: json({ + name: "test-name", + }), + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +// Mock responses for MixedParams scenario +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_DefaultClient_MixedParams = passOnSuccess( + [ + { + uri: "/azure/client-generator-core/client-initialization/default/mixed-params/with-query", + method: "get", + request: { + query: { + id: "test-id", + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/default/mixed-params/with-body", + method: "post", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + body: json({ + name: "test-name", + }), + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ], +); + +// Mock responses for PathParam scenario +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_DefaultClient_PathParam = passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/default/path/sample-blob/with-query", + method: "get", + request: { + query: { + format: "text", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/default/path/sample-blob/get-standalone", + method: "get", + request: {}, + response: { + status: 200, + body: json({ + name: "sample-blob", + size: 42, + contentType: "text/plain", + createdOn: "2025-04-01T12:00:00Z", + }), + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/default/path/sample-blob", + method: "delete", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, +]); + +// Mock responses for ParamAlias scenario +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_DefaultClient_ParamAlias = passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/default/param-alias/sample-blob/with-aliased-name", + method: "get", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/default/param-alias/sample-blob/with-original-name", + method: "get", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, +]); + +// Mock responses for QueryParam scenario +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_DefaultClient_QueryParam = passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/default/query/with-query", + method: "get", + request: { + query: { + blobName: "test-blob", + format: "text", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/default/query/get-standalone", + method: "get", + request: { + query: { + blobName: "test-blob", + }, + }, + response: { + status: 200, + body: json({ + name: "test-blob", + size: 42, + contentType: "text/plain", + createdOn: "2025-04-01T12:00:00Z", + }), + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/default/query/delete-resource", + method: "delete", + request: { + query: { + blobName: "test-blob", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, +]); diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individually/main.tsp b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individually/main.tsp new file mode 100644 index 0000000000..ffb3356111 --- /dev/null +++ b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individually/main.tsp @@ -0,0 +1,368 @@ +import "@typespec/http"; +import "@typespec/spector"; +import "@azure-tools/typespec-client-generator-core"; + +using Http; +using Spector; +using Azure.ClientGenerator.Core; + +@doc("Test for client initialization decorator - moving parameters from method to client level") +@scenarioService("/azure/client-generator-core/client-initialization/individually") +namespace _Specs_.Azure.ClientGenerator.Core.ClientInitialization.IndividuallyClient; + +@global.Azure.ClientGenerator.Core.clientNamespace( + "azure.clientgenerator.core.clientinitialization.individuallyclient", + "java" +) +model PathParamClientOptions { + @doc("The blob name to use for operations") + blobName: string; +} + +model BlobQueryParamClientOptions { + @doc("The blob name to use for operations") + blobName: string; +} + +model HeaderParamClientOptions { + @doc("The name to use for operations") + name: string; +} + +model MultipleParamsClientOptions { + @doc("The name to use for operations") + name: string; + + @doc("The region to use for operations") + region: string; +} + +model MixedParamsClientOptions { + @doc("The name to use for operations") + name: string; +} + +model ParamAliasClientOptions { + @doc("Blob name for the client.") + @global.Azure.ClientGenerator.Core.paramAlias("blob") + blobName: string; +} + +// Common parameter types and models + +model NameHeaderParam { + @header("name") + name: string; +} + +model RegionQueryParam { + @query + region: string; +} + +model BlobQueryParam { + @query + blobName: string; +} + +// Nested layer services for first-layer default (no decorator) +// Scenario 1: Default -> Individually initialization with path parameter +@scenarioDoc(""" + Client for testing default -> individually nested initialization. + + The parent client uses default initialization behavior, + and the child client uses individually initialization behavior. + + Parameters elevated to client level: + - blobName: "test-resource" (path parameter) + + Expected client usage: + ```ts + // directly (individually initialized) + const client = new IndividuallyNestedWithPathClient({ + blobName: "test-resource" + }); + + // Operations don't need blobName parameter + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually") +@global.Azure.ClientGenerator.Core.client({ + name: "IndividuallyNestedWithPathClient", +}) +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: PathParamClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually, +}) +@route("/nested-default-individually") +interface IndividuallyNestedWithPath { + @route("/{blobName}/with-query") + @get + withQuery(@path blobName: string, @query format?: string): void; + + @route("/{blobName}/get-standalone") + @get + getStandalone(@path blobName: string): BlobProperties; + + @route("/{blobName}") + @delete + deleteStandalone(@path blobName: string): void; +} + +// Nested layer services for first-layer default (no decorator) - Query variant +// Scenario 2: Default -> Individually initialization with query parameter +@scenarioDoc(""" + Client for testing default -> individually nested initialization. + + The parent client uses default initialization behavior, + and the child client uses individually initialization behavior. + + Parameters elevated to client level: + - blobName: "test-blob" (query parameter) + + Expected client usage: + ```ts + // directly (individually initialized) + const client = new IndividuallyNestedWithQueryClient({ + blobName: "test-blob" + }); + + // Operations don't need blobName parameter + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually with query parameters") +@global.Azure.ClientGenerator.Core.client({ + name: "IndividuallyNestedWithQueryClient", +}) +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: BlobQueryParamClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually, +}) +@route("/nested-default-individually-query") +interface IndividuallyNestedWithQuery { + @route("/with-query") + @get + withQuery(...BlobQueryParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...BlobQueryParam): BlobProperties; + + @route("/delete-resource") + @delete + deleteStandalone(...BlobQueryParam): void; +} + +// Nested layer services for default -> header parameters +// Scenario 3: Default -> Individually initialization with Header parameter +@scenarioDoc(""" + Client for testing default -> individually header parameter nested initialization. + + The parent client uses default initialization behavior, + and the child client moves header parameters to client level and uses individually initialization. + + Parameters elevated to client level: + - name: "test-name-value" (header parameter) + + Expected client usage: + ```ts + // directly (individually initialized) + const client = new IndividuallyNestedWithHeaderClient({ + name: "test-name-value" + }); + + // Operations don't need name header parameter + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually header parameters") +@global.Azure.ClientGenerator.Core.client({ + name: "IndividuallyNestedWithHeaderClient", +}) +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: HeaderParamClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually, +}) +@route("/nested-default-individually-header") +interface IndividuallyNestedWithHeader { + @route("/with-query") + @get + withQuery(...NameHeaderParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...NameHeaderParam): void; + + @route("/delete-standalone") + @delete + deleteStandalone(...NameHeaderParam): void; +} + +// Nested layer services for default -> multiple parameters +// Scenario 4: Default -> Individually Multiple parameters client +@scenarioDoc(""" + Client for testing default -> individually multiple parameters nested initialization. + + The parent client uses default initialization behavior, + and the child client moves multiple parameters (header and query) to client level with individually initialization. + + Parameters elevated to client level: + - name: "test-name-value" (header parameter) + - region: "us-west" (query parameter) + + Expected client usage: + ```ts + // directly (individually initialized) + const client = new IndividuallyNestedWithMultipleClient({ + name: "test-name-value", + region: "us-west" + }); + + // Operations don't need name or region parameters + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually multiple parameters") +@global.Azure.ClientGenerator.Core.client({ + name: "IndividuallyNestedWithMultipleClient", +}) +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: MultipleParamsClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually, +}) +@route("/nested-default-individually-multiple") +interface IndividuallyNestedWithMultiple { + @route("/with-query") + @get + withQuery(...NameHeaderParam, ...RegionQueryParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...NameHeaderParam, ...RegionQueryParam): void; + + @route("/delete-standalone") + @delete + deleteStandalone(...NameHeaderParam, ...RegionQueryParam): void; +} + +// Nested layer services for default -> mixed parameters +// Scenario 5: Default -> Individually Mixed parameters client +@scenarioDoc(""" + Client for testing default -> individually mixed parameters nested initialization. + + The parent client uses default initialization behavior, + and the child client moves some parameters to client level while keeping others at method level with individually initialization. + + Parameters elevated to client level: + - name: "test-name-value" (header parameter) + + Parameters remaining at method level: + - region: "us-west" (query parameter) + + Expected client usage: + ```ts + // directly (individually initialized) + const client = new IndividuallyNestedWithMixedClient({ + name: "test-name-value" + }); + + // Operations still need region parameter + client.withQuery(region: "us-west", format: "text"); + client.getStandalone(region: "us-west"); + client.deleteStandalone(region: "us-west"); + ``` + """) +@scenario +@doc("Operations for nested default -> individually mixed parameters") +@global.Azure.ClientGenerator.Core.client({ + name: "IndividuallyNestedWithMixedClient", +}) +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: MixedParamsClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually, +}) +@route("/nested-default-individually-mixed") +interface IndividuallyNestedWithMixed { + @route("/with-query") + @get + withQuery(...NameHeaderParam, ...RegionQueryParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...NameHeaderParam, ...RegionQueryParam): void; + + @route("/delete-standalone") + @delete + deleteStandalone(...NameHeaderParam, ...RegionQueryParam): void; +} + +// Nested layer services for param alias +// Scenario 6: Default -> Individually ParamAlias client +@scenarioDoc(""" + Client for testing default -> individually param alias nested initialization. + + The parent client uses default initialization behavior, + and the child client uses individually initialization with param alias. + + Parameters elevated to client level: + - blobName: "sample-blob" (path parameter with @paramAlias("blob")) + + Expected client usage: + ```ts + // directly (individually initialized) + const client = new IndividuallyNestedWithParamAliasClient({ + blobName: "sample-blob" + }); + + // Operations don't need blob/blobName parameter + client.withAliasedName(); + client.withOriginalName(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually param alias") +@global.Azure.ClientGenerator.Core.client({ + name: "IndividuallyNestedWithParamAliasClient", +}) +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: ParamAliasClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually, +}) +@route("/nested-default-individually-param-alias") +interface IndividuallyNestedWithParamAlias { + @route("/{blob}/with-aliased-name") + @get + withAliasedName( + @path + blob: string, + ): void; + + @route("/{blobName}/with-original-name") + @get + withOriginalName( + @path + blobName: string, + ): void; +} + +@doc("Properties of a blob") +model BlobProperties { + name: string; + size: int64; + contentType: string; + createdOn: utcDateTime; +} diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individually/mockapi.ts b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individually/mockapi.ts new file mode 100644 index 0000000000..4f2b828fbe --- /dev/null +++ b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individually/mockapi.ts @@ -0,0 +1,270 @@ +import { json, passOnSuccess, ScenarioMockApi } from "@typespec/spec-api"; + +export const Scenarios: Record = {}; + +// Mock responses for IndividuallyClient scenarios +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyClient_IndividuallyNestedWithPath = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually/test-blob/with-query", + method: "get", + request: { + query: { + format: "text", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually/test-blob/get-standalone", + method: "get", + request: {}, + response: { + status: 200, + body: json({ + name: "test-blob", + size: 1024, + contentType: "application/octet-stream", + createdOn: "2023-01-01T12:00:00Z", + }), + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually/test-blob", + method: "delete", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyClient_IndividuallyNestedWithQuery = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-query/with-query", + method: "get", + request: { + query: { + blobName: "test-blob", + format: "text", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-query/get-standalone", + method: "get", + request: { + query: { + blobName: "test-blob", + }, + }, + response: { + status: 200, + body: json({ + name: "test-blob", + size: 1024, + contentType: "application/octet-stream", + createdOn: "2023-01-01T12:00:00Z", + }), + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-query/delete-resource", + method: "delete", + request: { + query: { + blobName: "test-blob", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyClient_IndividuallyNestedWithHeader = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-header/with-query", + method: "get", + request: { + query: { + format: "text", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-header/get-standalone", + method: "get", + request: { + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-header/delete-standalone", + method: "delete", + request: { + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyClient_IndividuallyNestedWithMultiple = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-multiple/with-query", + method: "get", + request: { + query: { + format: "text", + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-multiple/get-standalone", + method: "get", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-multiple/delete-standalone", + method: "delete", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyClient_IndividuallyNestedWithMixed = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-mixed/with-query", + method: "get", + request: { + query: { + format: "text", + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-mixed/get-standalone", + method: "get", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-mixed/delete-standalone", + method: "delete", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +// Mock responses for IndividuallyNestedWithParamAlias scenario +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyClient_IndividuallyNestedWithParamAlias = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-param-alias/sample-blob/with-aliased-name", + method: "get", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually/nested-default-individually-param-alias/sample-blob/with-original-name", + method: "get", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individuallyParent/main.tsp b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individuallyParent/main.tsp new file mode 100644 index 0000000000..3bb7cccb6c --- /dev/null +++ b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individuallyParent/main.tsp @@ -0,0 +1,387 @@ +import "@typespec/http"; +import "@typespec/spector"; +import "@azure-tools/typespec-client-generator-core"; + +using Http; +using Spector; +using Azure.ClientGenerator.Core; + +@doc("Test for client initialization decorator - moving parameters from method to client level") +@scenarioService("/azure/client-generator-core/client-initialization/individually-parent") +namespace _Specs_.Azure.ClientGenerator.Core.ClientInitialization.IndividuallyParentClient; + +@global.Azure.ClientGenerator.Core.clientNamespace( + "azure.clientgenerator.core.clientinitialization.individuallyparentclient", + "java" +) +model PathParamClientOptions { + @doc("The blob name to use for operations") + blobName: string; +} + +model BlobQueryParamClientOptions { + @doc("The blob name to use for operations") + blobName: string; +} + +model HeaderParamClientOptions { + @doc("The name to use for operations") + name: string; +} + +model MultipleParamsClientOptions { + @doc("The name to use for operations") + name: string; + + @doc("The region to use for operations") + region: string; +} + +model MixedParamsClientOptions { + @doc("The name to use for operations") + name: string; +} + +model ParamAliasClientOptions { + @doc("Blob name for the client.") + @global.Azure.ClientGenerator.Core.paramAlias("blob") + blobName: string; +} + +// Common parameter types and models + +model NameHeaderParam { + @header("name") + name: string; +} + +model RegionQueryParam { + @query + region: string; +} + +model BlobQueryParam { + @query + blobName: string; +} + +// Nested layer services for first-layer default (no decorator) +// Scenario 1: Default -> Individually and Parent initialization with path parameter +@scenarioDoc(""" + Client for testing default -> individually and parent nested initialization. + + The parent client uses default initialization behavior, + and the child client uses both individually and parent initialization behavior. + + Parameters elevated to client level: + - blobName: "test-resource" (path parameter) + + Expected client usage: + ```ts + // via IndividuallyParentClient (parent initialization) + const client = IndividuallyParentClient.getIndividuallyParentNestedWithPathClient({ + blobName: "test-resource" + }); + + // directly (individually initialized) + const client = new IndividuallyParentNestedWithPathClient({ + blobName: "test-resource" + }); + + // Operations don't need blobName parameter + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually and parent") +@global.Azure.ClientGenerator.Core.operationGroup +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: PathParamClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually | global.Azure.ClientGenerator.Core.InitializedBy.parent, +}) +@route("/nested-default-individually-parent") +interface IndividuallyParentNestedWithPathClient { + @route("/{blobName}/with-query") + @get + withQuery(@path blobName: string, @query format?: string): void; + + @route("/{blobName}/get-standalone") + @get + getStandalone(@path blobName: string): BlobProperties; + + @route("/{blobName}") + @delete + deleteStandalone(@path blobName: string): void; +} + +// Nested layer services for first-layer default (no decorator) - Query variant +// Scenario 2: Default -> Individually and Parent initialization with query parameter +@scenarioDoc(""" + Client for testing default -> individually and parent nested initialization. + + The parent client uses default initialization behavior, + and the child client uses both individually and parent initialization behavior. + + Parameters elevated to client level: + - blobName: "test-blob" (query parameter) + + Expected client usage: + ```ts + // via IndividuallyParentClient (parent initialization) + const client = IndividuallyParentClient.getIndividuallyParentNestedWithQueryClient({ + blobName: "test-blob" + }); + + // directly (individually initialized) + const client = new IndividuallyParentNestedWithQueryClient({ + blobName: "test-blob" + }); + + // Operations don't need blobName parameter + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually and parent with query parameters") +@global.Azure.ClientGenerator.Core.operationGroup +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: BlobQueryParamClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually | global.Azure.ClientGenerator.Core.InitializedBy.parent, +}) +@route("/nested-default-individually-parent-query") +interface IndividuallyParentNestedWithQueryClient { + @route("/with-query") + @get + withQuery(...BlobQueryParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...BlobQueryParam): BlobProperties; + + @route("/delete-resource") + @delete + deleteStandalone(...BlobQueryParam): void; +} + +// Nested layer services for default -> header parameters +// Scenario 3: Default -> Individually and Parent initialization with Header parameter +@scenarioDoc(""" + Client for testing default -> individually and parent header parameter nested initialization. + + The parent client uses default initialization behavior, + and the child client moves header parameters to client level and uses both individually and parent initialization. + + Parameters elevated to client level: + - name: "test-name-value" (header parameter) + + Expected client usage: + ```ts + // via IndividuallyParentClient (parent initialization) + const client = IndividuallyParentClient.getIndividuallyParentNestedWithHeaderClient({ + name: "test-name-value" + }); + + // directly (individually initialized) + const client = new IndividuallyParentNestedWithHeaderClient({ + name: "test-name-value" + }); + + // Operations don't need name header parameter + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually and parent header parameters") +@global.Azure.ClientGenerator.Core.operationGroup +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: HeaderParamClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually | global.Azure.ClientGenerator.Core.InitializedBy.parent, +}) +@route("/nested-default-individually-parent-header") +interface IndividuallyParentNestedWithHeaderClient { + @route("/with-query") + @get + withQuery(...NameHeaderParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...NameHeaderParam): void; + + @route("/delete-standalone") + @delete + deleteStandalone(...NameHeaderParam): void; +} + +// Nested layer services for default -> multiple parameters +// Scenario 4: Default -> Individually and Parent Multiple parameters client +@scenarioDoc(""" + Client for testing default -> individually and parent multiple parameters nested initialization. + + The parent client uses default initialization behavior, + and the child client moves multiple parameters (header and query) to client level with both individually and parent initialization. + + Parameters elevated to client level: + - name: "test-name-value" (header parameter) + - region: "us-west" (query parameter) + + Expected client usage: + ```ts + // via IndividuallyParentClient (parent initialization) + const client = IndividuallyParentClient.getIndividuallyParentNestedWithMultipleClient({ + name: "test-name-value", + region: "us-west" + }); + + // directly (individually initialized) + const client = new IndividuallyParentNestedWithMultipleClient({ + name: "test-name-value", + region: "us-west" + }); + + // Operations don't need name or region parameters + client.withQuery(format: "text"); + client.getStandalone(); + client.deleteStandalone(); + ``` + """) +@scenario +@doc("Operations for nested default -> individually and parent multiple parameters") +@global.Azure.ClientGenerator.Core.operationGroup +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: MultipleParamsClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually | global.Azure.ClientGenerator.Core.InitializedBy.parent, +}) +@route("/nested-default-individually-parent-multiple") +interface IndividuallyParentNestedWithMultipleClient { + @route("/with-query") + @get + withQuery(...NameHeaderParam, ...RegionQueryParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...NameHeaderParam, ...RegionQueryParam): void; + + @route("/delete-standalone") + @delete + deleteStandalone(...NameHeaderParam, ...RegionQueryParam): void; +} + +// Nested layer services for default -> mixed parameters +// Scenario 5: Default -> Individually and Parent Mixed parameters client +@scenarioDoc(""" + Client for testing default -> individually and parent mixed parameters nested initialization. + + The parent client uses default initialization behavior, + and the child client moves some parameters to client level while keeping others at method level with both individually and parent initialization. + + Parameters elevated to client level: + - name: "test-name-value" (header parameter) + + Parameters remaining at method level: + - region: "us-west" (query parameter) + + Expected client usage: + ```ts + // via IndividuallyParentClient (parent initialization) + const client = IndividuallyParentClient.getIndividuallyParentNestedWithMixedClient({ + name: "test-name-value" + }); + + // directly (individually initialized) + const client = new IndividuallyParentNestedWithMixedClient({ + name: "test-name-value" + }); + + // Operations still need region parameter + client.withQuery(region: "us-west", format: "text"); + client.getStandalone(region: "us-west"); + client.deleteStandalone(region: "us-west"); + ``` + """) +@scenario +@doc("Operations for nested default -> individually and parent mixed parameters") +@global.Azure.ClientGenerator.Core.operationGroup +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: MixedParamsClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually | global.Azure.ClientGenerator.Core.InitializedBy.parent, +}) +@route("/nested-default-individually-parent-mixed") +interface IndividuallyParentNestedWithMixedClient { + @route("/with-query") + @get + withQuery(...NameHeaderParam, ...RegionQueryParam, @query format?: string): void; + + @route("/get-standalone") + @get + getStandalone(...NameHeaderParam, ...RegionQueryParam): void; + + @route("/delete-standalone") + @delete + deleteStandalone(...NameHeaderParam, ...RegionQueryParam): void; +} + +// Nested layer services for param alias +// Scenario 6: Default -> Individually and Parent parameter alias client +@scenarioDoc(""" + Client for testing default -> individually and parent parameter alias nested initialization. + + The parent client uses default initialization behavior, + and the child client renames parameters at client level using @paramAlias with both individually and parent initialization. + + Parameters elevated to client level: + - blobName: "test-blob" → renamed to "renamedBlobName" using @paramAlias (query parameter) + + Expected client usage: + ```ts + // via IndividuallyParentClient (parent initialization) + const client = IndividuallyParentClient.getIndividuallyParentNestedWithParamAliasClient({ + renamedBlobName: "test-blob" // Renamed from blobName + }); + + // directly (individually initialized) + const client = new IndividuallyParentNestedWithParamAliasClient({ + renamedBlobName: "test-blob" // Renamed from blobName + }); + + // Operations use blob or blobName at method level + client.withAliasedName(blob: "test-blob-path"); + client.withOriginalName(blobName: "test-blob-path"); + ``` + """) +@scenario +@doc("Operations for nested default -> individually and parent param alias") +@global.Azure.ClientGenerator.Core.operationGroup +@global.Azure.ClientGenerator.Core.clientInitialization({ + parameters: ParamAliasClientOptions, + initializedBy: global.Azure.ClientGenerator.Core.InitializedBy.individually | global.Azure.ClientGenerator.Core.InitializedBy.parent, +}) +@route("/nested-default-individually-parent-param-alias") +interface IndividuallyParentNestedWithParamAliasClient { + @route("/{blob}/with-aliased-name") + @get + withAliasedName( + @path + blob: string, + ): void; + + @route("/{blobName}/with-original-name") + @get + withOriginalName( + @path + blobName: string, + ): void; +} + +@doc("Properties of a blob") +model BlobProperties { + name: string; + size: int64; + contentType: string; + createdOn: utcDateTime; +} diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individuallyParent/mockapi.ts b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individuallyParent/mockapi.ts new file mode 100644 index 0000000000..cca3da5678 --- /dev/null +++ b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/individuallyParent/mockapi.ts @@ -0,0 +1,269 @@ +import { json, passOnSuccess, ScenarioMockApi } from "@typespec/spec-api"; + +export const Scenarios: Record = {}; + +// Mock responses for IndividuallyParentClient scenarios +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyParentClient_IndividuallyParentNestedWithPathClient = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent/test-blob/with-query", + method: "get", + request: { + query: { + format: "text", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent/test-blob/get-standalone", + method: "get", + request: {}, + response: { + status: 200, + body: json({ + name: "test-blob", + size: 1024, + contentType: "application/octet-stream", + createdOn: "2023-01-01T12:00:00Z", + }), + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent/test-blob", + method: "delete", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyParentClient_IndividuallyParentNestedWithQueryClient = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-query/with-query", + method: "get", + request: { + query: { + blobName: "test-blob", + format: "text", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-query/get-standalone", + method: "get", + request: { + query: { + blobName: "test-blob", + }, + }, + response: { + status: 200, + body: json({ + name: "test-blob", + size: 1024, + contentType: "application/octet-stream", + createdOn: "2023-01-01T12:00:00Z", + }), + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-query/delete-resource", + method: "delete", + request: { + query: { + blobName: "test-blob", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyParentClient_IndividuallyParentNestedWithHeaderClient = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-header/with-query", + method: "get", + request: { + query: { + format: "text", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-header/get-standalone", + method: "get", + request: { + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-header/delete-standalone", + method: "delete", + request: { + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyParentClient_IndividuallyParentNestedWithMultipleClient = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-multiple/with-query", + method: "get", + request: { + query: { + format: "text", + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-multiple/get-standalone", + method: "get", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-multiple/delete-standalone", + method: "delete", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyParentClient_IndividuallyParentNestedWithMixedClient = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-mixed/with-query", + method: "get", + request: { + query: { + format: "text", + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-mixed/get-standalone", + method: "get", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-mixed/delete-standalone", + method: "delete", + request: { + query: { + region: "us-west", + }, + headers: { + name: "test-name-value", + }, + }, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); + +Scenarios.Azure_ClientGenerator_Core_ClientInitialization_IndividuallyParentClient_IndividuallyParentNestedWithParamAliasClient = + passOnSuccess([ + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-param-alias/sample-blob/with-aliased-name", + method: "get", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + { + uri: "/azure/client-generator-core/client-initialization/individually-parent/nested-default-individually-parent-param-alias/sample-blob/with-original-name", + method: "get", + request: {}, + response: { + status: 204, + }, + kind: "MockApiDefinition", + }, + ]); diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/main.tsp b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/main.tsp deleted file mode 100644 index 883e1218aa..0000000000 --- a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/main.tsp +++ /dev/null @@ -1,133 +0,0 @@ -import "@typespec/http"; -import "@typespec/spector"; -import "@azure-tools/typespec-client-generator-core"; - -using Http; -using Spector; -using Azure.ClientGenerator.Core; - -@doc("Test for client initialization decorator - moving parameters from method to client level") -@scenarioService("/azure/client-generator-core/client-initialization") -namespace Service; - -// Common parameter types and models - -model NameHeaderParam { - @header("name") - name: string; -} - -model RegionQueryParam { - @query - region: string; -} - -model Input { - name: string; -} - -// Scenario 1: Header parameter moved to client level - -@route("/header-param") -interface HeaderParam { - @route("/with-query") - @get - withQuery(...NameHeaderParam, @query id: string): void; - - @route("/with-body") - @post - withBody(...NameHeaderParam, @body body: Input): void; -} - -// Scenario 2: Multiple parameters (header and query) moved to client level - -@route("/multiple-params") -interface MultipleParams { - @route("/with-query") - @get - withQuery(...NameHeaderParam, ...RegionQueryParam, @query id: string): void; - - @route("/with-body") - @post - withBody(...NameHeaderParam, ...RegionQueryParam, @body body: Input): void; -} - -// Scenario 3: Mix of client-level and method-level parameters - -@route("/mixed-params") -interface MixedParams { - @route("/with-query") - @get - withQuery(...NameHeaderParam, ...RegionQueryParam, @query id: string): void; - - @route("/with-body") - @post - withBody( - ...NameHeaderParam, - ...RegionQueryParam, - @body body: { - name: string; - }, - ): void; -} - -// Scenario 4: Path parameter moved to client level -@doc("Blob operations with path parameter that should be moved to client level") -@route("/path") -interface PathParam { - @route("/{blobName}/with-query") - @get - withQuery(@path blobName: string, @query format?: string): void; - - @route("/{blobName}/get-standalone") - @get - getStandalone(@path blobName: string): BlobProperties; - - @route("/{blobName}") - @delete - deleteStandalone(@path blobName: string): void; -} - -// Scenario 5: Parameter aliases for better client API names -@doc("Operations demonstrating the @paramAlias decorator for renaming parameters in client code") -@route("/param-alias") -interface ParamAlias { - @route("/{blob}/with-aliased-name") - @get - withAliasedName( - @path - blob: string, - ): void; - - @route("/{blobName}/with-original-name") - @get - withOriginalName( - @path - blobName: string, - ): void; -} - -@doc("Properties of a blob") -model BlobProperties { - name: string; - size: int64; - contentType: string; - createdOn: utcDateTime; -} - -// Scenario 6: Client initialization on child client -@doc("Blob operations with path parameter that should be moved to client level, in child client") -@route("/child-client") -interface ChildClient { - @route("/{blobName}/with-query") - @get - withQuery(@path blobName: string, @query format?: string): void; - - @route("/{blobName}/get-standalone") - @get - getStandalone(@path blobName: string): BlobProperties; - - @route("/{blobName}") - @delete - deleteStandalone(@path blobName: string): void; -} diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/mockapi.ts b/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/mockapi.ts deleted file mode 100644 index 0b6df10133..0000000000 --- a/packages/azure-http-specs/specs/azure/client-generator-core/client-initialization/mockapi.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { json, passOnSuccess, ScenarioMockApi } from "@typespec/spec-api"; - -export const Scenarios: Record = {}; - -// Mock responses for HeaderParam scenario -Scenarios.Azure_ClientGenerator_Core_ClientInitialization_HeaderParam = passOnSuccess([ - { - uri: "/azure/client-generator-core/client-initialization/header-param/with-query", - method: "get", - request: { - query: { - id: "test-id", - }, - headers: { - name: "test-name-value", - }, - }, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, - { - uri: "/azure/client-generator-core/client-initialization/header-param/with-body", - method: "post", - request: { - headers: { - name: "test-name-value", - }, - body: json({ - name: "test-name", - }), - }, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, -]); - -// Mock responses for MultipleParams scenario -Scenarios.Azure_ClientGenerator_Core_ClientInitialization_MultipleParams = passOnSuccess([ - { - uri: "/azure/client-generator-core/client-initialization/multiple-params/with-query", - method: "get", - request: { - query: { - id: "test-id", - region: "us-west", - }, - headers: { - name: "test-name-value", - }, - }, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, - { - uri: "/azure/client-generator-core/client-initialization/multiple-params/with-body", - method: "post", - request: { - query: { - region: "us-west", - }, - headers: { - name: "test-name-value", - }, - body: json({ - name: "test-name", - }), - }, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, -]); - -// Mock responses for MixedParams scenario -Scenarios.Azure_ClientGenerator_Core_ClientInitialization_MixedParams = passOnSuccess([ - { - uri: "/azure/client-generator-core/client-initialization/mixed-params/with-query", - method: "get", - request: { - query: { - id: "test-id", - region: "us-west", - }, - headers: { - name: "test-name-value", - }, - }, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, - { - uri: "/azure/client-generator-core/client-initialization/mixed-params/with-body", - method: "post", - request: { - query: { - region: "us-west", - }, - headers: { - name: "test-name-value", - }, - body: json({ - name: "test-name", - }), - }, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, -]); - -// Mock responses for PathParam scenario -Scenarios.Azure_ClientGenerator_Core_ClientInitialization_PathParam = passOnSuccess([ - { - uri: "/azure/client-generator-core/client-initialization/path/sample-blob/with-query", - method: "get", - request: { - query: { - format: "text", - }, - }, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, - { - uri: "/azure/client-generator-core/client-initialization/path/sample-blob/get-standalone", - method: "get", - request: {}, - response: { - status: 200, - body: json({ - name: "sample-blob", - size: 42, - contentType: "text/plain", - createdOn: "2025-04-01T12:00:00Z", - }), - }, - kind: "MockApiDefinition", - }, - { - uri: "/azure/client-generator-core/client-initialization/path/sample-blob", - method: "delete", - request: {}, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, -]); - -// Mock responses for ParamAlias scenario -Scenarios.Azure_ClientGenerator_Core_ClientInitialization_ParamAlias = passOnSuccess([ - { - uri: "/azure/client-generator-core/client-initialization/param-alias/sample-blob/with-aliased-name", - method: "get", - request: {}, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, - { - uri: "/azure/client-generator-core/client-initialization/param-alias/sample-blob/with-original-name", - method: "get", - request: {}, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, -]); - -// Mock responses for ParentClient/ChildClient scenario -Scenarios.Azure_ClientGenerator_Core_ClientInitialization_ParentClient_ChildClient = passOnSuccess([ - { - uri: "/azure/client-generator-core/client-initialization/child-client/sample-blob/with-query", - method: "get", - request: { - query: { - format: "text", - }, - }, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, - { - uri: "/azure/client-generator-core/client-initialization/child-client/sample-blob/get-standalone", - method: "get", - request: {}, - response: { - status: 200, - body: json({ - name: "sample-blob", - size: 42, - contentType: "text/plain", - createdOn: "2025-04-01T12:00:00Z", - }), - }, - kind: "MockApiDefinition", - }, - { - uri: "/azure/client-generator-core/client-initialization/child-client/sample-blob", - method: "delete", - request: {}, - response: { - status: 204, - }, - kind: "MockApiDefinition", - }, -]);