diff --git a/.chronus/changes/fix_route_param-2024-9-31-18-1-39.md b/.chronus/changes/fix_route_param-2024-9-31-18-1-39.md new file mode 100644 index 0000000000..95a617fe4b --- /dev/null +++ b/.chronus/changes/fix_route_param-2024-9-31-18-1-39.md @@ -0,0 +1,7 @@ +--- +changeKind: fix +packages: + - "@azure-tools/typespec-client-generator-core" +--- + +remove unused path parameter from method diff --git a/packages/typespec-client-generator-core/src/http.ts b/packages/typespec-client-generator-core/src/http.ts index 05f37afa6a..ba5002b7b3 100644 --- a/packages/typespec-client-generator-core/src/http.ts +++ b/packages/typespec-client-generator-core/src/http.ts @@ -85,6 +85,7 @@ export function getSdkHttpOperation( const parameters = diagnostics.pipe( getSdkHttpParameters(context, httpOperation, methodParameters, responsesWithBodies[0]), ); + filterOutUselessPathParameters(context, httpOperation, methodParameters); return diagnostics.wrap({ __raw: httpOperation, kind: "http", @@ -628,6 +629,31 @@ function findMapping( return undefined; } +function filterOutUselessPathParameters( + context: TCGCContext, + httpOperation: HttpOperation, + methodParameters: SdkMethodParameter[], +) { + // there are some cases that method path parameter is not in operation: + // 1. autoroute with constant parameter + // 2. singleton arm resource name + // 3. visibility mis-match + // so we will remove the method parameter for consistent + for (let i = 0; i < methodParameters.length; i++) { + const param = methodParameters[i]; + if ( + param.__raw && + isPathParam(context.program, param.__raw) && + httpOperation.parameters.parameters.filter( + (p) => p.type === "path" && p.name === getWireName(context, param.__raw!), + ).length === 0 + ) { + methodParameters.splice(i, 1); + i--; + } + } +} + function findRootSourceProperty(property: ModelProperty): ModelProperty { while (property.sourceProperty) { property = property.sourceProperty; diff --git a/packages/typespec-client-generator-core/test/package.test.ts b/packages/typespec-client-generator-core/test/package.test.ts index 174eb04175..8f20ab3bcb 100644 --- a/packages/typespec-client-generator-core/test/package.test.ts +++ b/packages/typespec-client-generator-core/test/package.test.ts @@ -350,10 +350,10 @@ describe("typespec-client-generator-core: package", () => { const method = getServiceMethodOfClient(sdkPackage); strictEqual(method.name, "create"); strictEqual(method.kind, "basic"); - strictEqual(method.parameters.length, 5); + strictEqual(method.parameters.length, 4); deepStrictEqual( method.parameters.map((x) => x.name), - ["id", "weight", "color", "contentType", "accept"], + ["weight", "color", "contentType", "accept"], ); const bodyParameter = method.operation.bodyParam; diff --git a/packages/typespec-client-generator-core/test/packages/parameters.test.ts b/packages/typespec-client-generator-core/test/packages/parameters.test.ts index c2e64e935e..7ce538e6b0 100644 --- a/packages/typespec-client-generator-core/test/packages/parameters.test.ts +++ b/packages/typespec-client-generator-core/test/packages/parameters.test.ts @@ -1,4 +1,6 @@ import { AzureCoreTestLibrary } from "@azure-tools/typespec-azure-core/testing"; +import { AzureResourceManagerTestLibrary } from "@azure-tools/typespec-azure-resource-manager/testing"; +import { OpenAPITestLibrary } from "@typespec/openapi/testing"; import { deepStrictEqual, ok, strictEqual } from "assert"; import { beforeEach, describe, it } from "vitest"; import { @@ -1087,4 +1089,52 @@ describe("typespec-client-generator-core: parameters", () => { strictEqual(method.operation.bodyParam?.serializedName, "body"); }); }); + + describe("method parameter not used in operation", () => { + it("autoroute with constant", async () => { + await runner.compileWithBuiltInService(` + @autoRoute + op test(@path param: "test"): void; + `); + const sdkPackage = runner.context.sdkPackage; + const method = getServiceMethodOfClient(sdkPackage); + strictEqual(method.parameters.length, 0); + strictEqual(method.operation.parameters.length, 0); + strictEqual(method.operation.uriTemplate, "/test"); + }); + + it("singleton resource", async () => { + const runnerWithArm = await createSdkTestRunner({ + librariesToAdd: [AzureResourceManagerTestLibrary, AzureCoreTestLibrary, OpenAPITestLibrary], + autoUsings: ["Azure.ResourceManager", "Azure.Core"], + emitterName: "@azure-tools/typespec-java", + }); + await runnerWithArm.compileWithBuiltInAzureResourceManagerService(` + @singleton("default") + model SingletonTrackedResource is TrackedResource { + ...ResourceNameParameter; + } + + model SingletonTrackedResourceProperties { + description?: string; + } + + @armResourceOperations + interface Singleton { + createOrUpdate is ArmResourceCreateOrReplaceAsync; + } + `); + + const sdkPackage = runnerWithArm.context.sdkPackage; + const method = getServiceMethodOfClient(sdkPackage); + deepStrictEqual( + method.parameters.map((p) => p.name), + ["resourceGroupName", "resource", "contentType", "accept"], + ); + deepStrictEqual( + method.operation.parameters.map((p) => p.name), + ["apiVersion", "subscriptionId", "resourceGroupName", "contentType", "accept"], + ); + }); + }); });