diff --git a/.chronus/changes/cookie_support-2024-10-6-16-23-46.md b/.chronus/changes/cookie_support-2024-10-6-16-23-46.md new file mode 100644 index 0000000000..9251b7fd95 --- /dev/null +++ b/.chronus/changes/cookie_support-2024-10-6-16-23-46.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@azure-tools/typespec-client-generator-core" +--- + +add `SdkCookieParameter` type and support `@cookie` in TypeSpec http lib \ No newline at end of file diff --git a/packages/typespec-client-generator-core/src/http.ts b/packages/typespec-client-generator-core/src/http.ts index 8d08f2bfa3..5685d041bb 100644 --- a/packages/typespec-client-generator-core/src/http.ts +++ b/packages/typespec-client-generator-core/src/http.ts @@ -15,12 +15,14 @@ import { HttpOperationParameter, HttpOperationPathParameter, HttpOperationQueryParameter, + getCookieParamOptions, getHeaderFieldName, getHeaderFieldOptions, getPathParamName, getQueryParamName, getQueryParamOptions, isBody, + isCookieParam, isHeader, isPathParam, isQueryParam, @@ -30,6 +32,7 @@ import { getParamAlias } from "./decorators.js"; import { CollectionFormat, SdkBodyParameter, + SdkCookieParameter, SdkHeaderParameter, SdkHttpErrorResponse, SdkHttpOperation, @@ -104,12 +107,13 @@ export function isSdkHttpParameter(context: TCGCContext, type: ModelProperty): b isPathParam(program, type) || isQueryParam(program, type) || isHeader(program, type) || - isBody(program, type) + isBody(program, type) || + isCookieParam(program, type) ); } interface SdkHttpParameters { - parameters: (SdkPathParameter | SdkQueryParameter | SdkHeaderParameter)[]; + parameters: (SdkPathParameter | SdkQueryParameter | SdkHeaderParameter | SdkCookieParameter)[]; bodyParam?: SdkBodyParameter; } @@ -128,14 +132,8 @@ function getSdkHttpParameters( retval.parameters = httpOperation.parameters.parameters .filter((x) => !isNeverOrVoidType(x.param.type)) .map((x) => - diagnostics.pipe( - getSdkHttpParameter(context, x.param, httpOperation.operation, x, x.type as any), - ), - ) - .filter( - (x): x is SdkHeaderParameter | SdkQueryParameter | SdkPathParameter => - x.kind === "header" || x.kind === "query" || x.kind === "path", - ); + diagnostics.pipe(getSdkHttpParameter(context, x.param, httpOperation.operation, x, x.type)), + ) as (SdkPathParameter | SdkQueryParameter | SdkHeaderParameter | SdkCookieParameter)[]; const headerParams = retval.parameters.filter( (x): x is SdkHeaderParameter => x.kind === "header", ); @@ -336,7 +334,7 @@ export function getSdkHttpParameter( param: ModelProperty, operation?: Operation, httpParam?: HttpOperationParameter, - location?: "path" | "query" | "header" | "body", + location?: "path" | "query" | "header" | "body" | "cookie", ): [SdkHttpParameter, readonly Diagnostic[]] { const diagnostics = createDiagnosticCollector(); const base = diagnostics.pipe(getSdkModelPropertyTypeBase(context, param, operation)); @@ -363,6 +361,15 @@ export function getSdkHttpParameter( optional: false, }); } + if (isCookieParam(context.program, param) || location === "cookie") { + return diagnostics.wrap({ + ...base, + kind: "cookie", + serializedName: getCookieParamOptions(program, param)?.name ?? base.name, + correspondingMethodParams, + optional: param.optional, + }); + } if (isBody(context.program, param) || location === "body") { return diagnostics.wrap({ ...base, diff --git a/packages/typespec-client-generator-core/src/interfaces.ts b/packages/typespec-client-generator-core/src/interfaces.ts index 1abadadc74..f1ee226d54 100644 --- a/packages/typespec-client-generator-core/src/interfaces.ts +++ b/packages/typespec-client-generator-core/src/interfaces.ts @@ -429,7 +429,8 @@ export type SdkModelPropertyType = | SdkQueryParameter | SdkPathParameter | SdkBodyParameter - | SdkHeaderParameter; + | SdkHeaderParameter + | SdkCookieParameter; export interface MultipartOptions { // whether this part is for file @@ -489,6 +490,12 @@ export interface SdkPathParameter extends SdkModelPropertyTypeBase { correspondingMethodParams: SdkModelPropertyType[]; } +export interface SdkCookieParameter extends SdkModelPropertyTypeBase { + kind: "cookie"; + serializedName: string; + correspondingMethodParams: SdkModelPropertyType[]; +} + export interface SdkBodyParameter extends SdkModelPropertyTypeBase { kind: "body"; serializedName: string; @@ -502,7 +509,8 @@ export type SdkHttpParameter = | SdkQueryParameter | SdkPathParameter | SdkBodyParameter - | SdkHeaderParameter; + | SdkHeaderParameter + | SdkCookieParameter; export interface SdkMethodParameter extends SdkModelPropertyTypeBase { kind: "method"; @@ -554,7 +562,7 @@ export interface SdkHttpOperation extends SdkServiceOperationBase { path: string; uriTemplate: string; verb: HttpVerb; - parameters: (SdkPathParameter | SdkQueryParameter | SdkHeaderParameter)[]; + parameters: (SdkPathParameter | SdkQueryParameter | SdkHeaderParameter | SdkCookieParameter)[]; bodyParam?: SdkBodyParameter; responses: SdkHttpResponse[]; exceptions: SdkHttpErrorResponse[]; 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 42705c2284..02ff61aff8 100644 --- a/packages/typespec-client-generator-core/test/packages/parameters.test.ts +++ b/packages/typespec-client-generator-core/test/packages/parameters.test.ts @@ -305,6 +305,24 @@ describe("typespec-client-generator-core: parameters", () => { strictEqual(queryParm.collectionFormat, "csv"); }); + it("cookie basic", async () => { + await runner.compile(`@server("http://localhost:3000", "endpoint") + @service({}) + namespace My.Service; + + op myOp(@cookie(#{name: "token"}) auth: string): void; + `); + const sdkPackage = runner.context.sdkPackage; + const method = getServiceMethodOfClient(sdkPackage); + strictEqual(method.kind, "basic"); + + strictEqual(method.operation.parameters.length, 1); + const cookieParam = method.operation.parameters[0]; + strictEqual(cookieParam.name, "auth"); + strictEqual(cookieParam.kind, "cookie"); + strictEqual(cookieParam.serializedName, "token"); + }); + it("body basic", async () => { await runner.compile(`@server("http://localhost:3000", "endpoint") @service({})