From 5e92ed8b07dd0b7c3294b6fdcacf7d1e62824132 Mon Sep 17 00:00:00 2001 From: Qiaoqiao Zhang <55688292+qiaozha@users.noreply.github.com> Date: Wed, 27 Sep 2023 14:21:03 +0800 Subject: [PATCH] Try not flatten payload (#2020) * try-not-flatten-payload * fix tests * should not generate duplicate models and should not generate body schema properties in options * fix model property as path parameter * format * fix ci * add ut for alias flattening * add ut for not flatten if spread models * add deserialize for flattened body * enable cadl ranch test for spread in modular --- .../review/ai-content-safety.api.md | 43 +- .../typespec-ts/src/ContentSafetyClient.ts | 35 +- .../typespec-ts/src/api/operations.ts | 59 ++- .../generated/typespec-ts/src/index.ts | 4 + .../generated/typespec-ts/src/models/index.ts | 4 + .../typespec-ts/src/models/models.ts | 36 ++ .../typespec-ts/src/models/options.ts | 28 +- .../typespec-ts/review/eventgrid.api.md | 25 +- .../typespec-ts/src/EventGridClient.ts | 23 +- .../typespec-ts/src/api/operations.ts | 39 +- .../generated/typespec-ts/src/index.ts | 3 + .../generated/typespec-ts/src/models/index.ts | 3 + .../typespec-ts/src/models/models.ts | 18 + .../typespec-ts/review/load-testing.api.md | 80 +-- .../LoadTestAdministrationClient.ts | 25 +- .../loadTestAdministration/api/operations.ts | 110 ++-- .../loadTestAdministration/models/options.ts | 74 +-- .../src/loadTestRun/LoadTestRunClient.ts | 25 +- .../src/loadTestRun/api/operations.ts | 109 ++-- .../typespec-ts/src/loadTestRun/index.ts | 1 + .../src/loadTestRun/models/index.ts | 1 + .../src/loadTestRun/models/models.ts | 11 + .../src/loadTestRun/models/options.ts | 102 +--- .../typespec-ts/review/openai_modular.api.md | 110 ++-- .../generated/typespec-ts/src/OpenAIClient.ts | 25 +- .../typespec-ts/src/api/operations.ts | 176 +++--- .../generated/typespec-ts/src/index.ts | 4 + .../generated/typespec-ts/src/models/index.ts | 4 + .../typespec-ts/src/models/models.ts | 229 ++++++++ .../typespec-ts/src/models/options.ts | 281 +--------- .../typespec-ts/review/widget_dpg.api.md | 16 +- .../generated/src/WidgetServiceClient.ts | 15 +- .../sources/generated/src/api/operations.ts | 23 +- .../sources/generated/src/index.ts | 2 + .../sources/generated/src/models/index.ts | 2 +- .../sources/generated/src/models/models.ts | 14 + .../sources/generated/src/models/options.ts | 7 +- .../typespec-ts/src/WidgetServiceClient.ts | 15 +- .../typespec-ts/src/api/operations.ts | 23 +- .../generated/typespec-ts/src/index.ts | 2 + .../generated/typespec-ts/src/models/index.ts | 2 +- .../typespec-ts/src/models/models.ts | 14 + .../typespec-ts/src/models/options.ts | 7 +- .../typespec-ts/src/modular/buildCodeModel.ts | 55 +- .../src/modular/buildOperations.ts | 5 +- .../typespec-ts/src/modular/emitModels.ts | 3 +- .../src/modular/helpers/operationHelpers.ts | 84 ++- .../src/modular/helpers/typeHelpers.ts | 5 +- .../src/modular/modularCodeModel.ts | 1 + .../test/commands/cadl-ranch-list.ts | 4 + .../modularIntegration/encodeBytes.spec.ts | 31 +- .../modularIntegration/encodeDatetime.spec.ts | 29 +- .../modularIntegration/encodeDuration.spec.ts | 13 +- .../generated/azure/core/src/BasicClient.ts | 8 +- .../azure/core/src/api/operations.ts | 20 +- .../azure/core/src/models/options.ts | 8 +- .../generated/encode/bytes/src/BytesClient.ts | 16 +- .../encode/bytes/src/api/property.ts | 34 +- .../encode/datetime/src/DatetimeClient.ts | 20 +- .../encode/datetime/src/api/property.ts | 40 +- .../encode/duration/src/DurationClient.ts | 20 +- .../encode/duration/src/api/property.ts | 40 +- .../models/usage/generated/src/UsageClient.ts | 14 +- .../usage/generated/src/api/operations.ts | 22 +- .../models/usage/generated/src/index.ts | 1 + .../usage/generated/src/models/index.ts | 2 +- .../usage/generated/src/models/models.ts | 5 + .../parameters/spread/src/SpreadClient.ts | 85 +++ .../spread/src/api/SpreadContext.ts | 16 + .../parameters/spread/src/api/alias.ts | 158 ++++++ .../parameters/spread/src/api/index.ts | 14 + .../parameters/spread/src/api/model.ts | 45 ++ .../generated/parameters/spread/src/index.ts | 11 + .../generated/parameters/spread/src/logger.ts | 5 + .../parameters/spread/src/models/index.ts | 10 + .../parameters/spread/src/models/models.ts | 7 + .../parameters/spread/src/models/options.ts | 14 + .../spread/src/rest/clientDefinitions.ts | 61 +++ .../parameters/spread/src/rest/index.ts | 12 + .../parameters/spread/src/rest/models.ts | 7 + .../parameters/spread/src/rest/parameters.ts | 61 +++ .../parameters/spread/src/rest/responses.ts | 25 + .../spread/src/rest/spreadClient.ts | 35 ++ .../parameters/spread/tspconfig.yaml | 14 + .../spreadParameters.spec.ts | 58 ++ .../test/modularIntegration/usage.spec.ts | 10 +- .../test/modularUnit/modelsGenerator.spec.ts | 500 ++++++++++++++++-- packages/typespec-ts/test/util/emitUtil.ts | 17 +- 88 files changed, 2216 insertions(+), 1258 deletions(-) create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/SpreadClient.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/SpreadContext.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/alias.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/model.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/logger.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/models.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/options.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/clientDefinitions.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/models.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/parameters.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/responses.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/spreadClient.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/spread/tspconfig.yaml create mode 100644 packages/typespec-ts/test/modularIntegration/spreadParameters.spec.ts diff --git a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/review/ai-content-safety.api.md b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/review/ai-content-safety.api.md index 3949faeb43..f91c7780e2 100644 --- a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/review/ai-content-safety.api.md +++ b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/review/ai-content-safety.api.md @@ -9,6 +9,11 @@ import { KeyCredential } from '@azure/core-auth'; import { OperationOptions } from '@azure-rest/core-client'; import { TokenCredential } from '@azure/core-auth'; +// @public +export interface AddOrUpdateBlockItemsOptions { + blockItems: TextBlockItemInfo[]; +} + // @public (undocumented) export interface AddOrUpdateBlockItemsRequestOptions extends OperationOptions { } @@ -18,13 +23,18 @@ export interface AddOrUpdateBlockItemsResult { value?: TextBlockItem[]; } +// @public +export interface AnalyzeImageOptions { + categories?: ImageCategory[]; + image: ImageData_2; + outputType?: AnalyzeImageOutputType; +} + // @public export type AnalyzeImageOutputType = string; // @public (undocumented) export interface AnalyzeImageRequestOptions extends OperationOptions { - categories?: ImageCategory[]; - outputType?: AnalyzeImageOutputType; } // @public @@ -33,14 +43,19 @@ export interface AnalyzeImageResult { } // @public -export type AnalyzeTextOutputType = string; - -// @public (undocumented) -export interface AnalyzeTextRequestOptions extends OperationOptions { +export interface AnalyzeTextOptions { blocklistNames?: string[]; breakByBlocklists?: boolean; categories?: TextCategory[]; outputType?: AnalyzeTextOutputType; + text: string; +} + +// @public +export type AnalyzeTextOutputType = string; + +// @public (undocumented) +export interface AnalyzeTextRequestOptions extends OperationOptions { } // @public @@ -52,16 +67,16 @@ export interface AnalyzeTextResult { // @public (undocumented) export class ContentSafetyClient { constructor(endpoint: string, credential: KeyCredential | TokenCredential, options?: ContentSafetyClientOptions); - addOrUpdateBlockItems(blockItems: TextBlockItemInfo[], blocklistName: string, options?: AddOrUpdateBlockItemsRequestOptions): Promise; - analyzeImage(image: ImageData_2, options?: AnalyzeImageRequestOptions): Promise; - analyzeText(text: string, options?: AnalyzeTextRequestOptions): Promise; - createOrUpdateTextBlocklist(blocklistName: string, options?: CreateOrUpdateTextBlocklistOptions): Promise; + addOrUpdateBlockItems(blocklistName: string, body: AddOrUpdateBlockItemsOptions, options?: AddOrUpdateBlockItemsRequestOptions): Promise; + analyzeImage(body: AnalyzeImageOptions, options?: AnalyzeImageRequestOptions): Promise; + analyzeText(body: AnalyzeTextOptions, options?: AnalyzeTextRequestOptions): Promise; + createOrUpdateTextBlocklist(blocklistName: string, resource: TextBlocklist, options?: CreateOrUpdateTextBlocklistOptions): Promise; deleteTextBlocklist(blocklistName: string, options?: DeleteTextBlocklistOptions): Promise; getTextBlocklist(blocklistName: string, options?: GetTextBlocklistOptions): Promise; getTextBlocklistItem(blocklistName: string, blockItemId: string, options?: GetTextBlocklistItemOptions): Promise; listTextBlocklistItems(blocklistName: string, options?: ListTextBlocklistItemsOptions): Promise; listTextBlocklists(options?: ListTextBlocklistsOptions): Promise; - removeBlockItems(blockItemIds: string[], blocklistName: string, options?: RemoveBlockItemsRequestOptions): Promise; + removeBlockItems(blocklistName: string, body: RemoveBlockItemsOptions, options?: RemoveBlockItemsRequestOptions): Promise; } // @public (undocumented) @@ -71,7 +86,6 @@ export interface ContentSafetyClientOptions extends ClientOptions { // @public (undocumented) export interface CreateOrUpdateTextBlocklistOptions extends OperationOptions { contentType?: string; - description?: string; } // @public (undocumented) @@ -125,6 +139,11 @@ export interface PagedTextBlocklist { value: TextBlocklist[]; } +// @public +export interface RemoveBlockItemsOptions { + blockItemIds: string[]; +} + // @public (undocumented) export interface RemoveBlockItemsRequestOptions extends OperationOptions { } diff --git a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/ContentSafetyClient.ts b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/ContentSafetyClient.ts index 87a787dc58..ce270c1e56 100644 --- a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/ContentSafetyClient.ts +++ b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/ContentSafetyClient.ts @@ -3,13 +3,15 @@ import { TokenCredential, KeyCredential } from "@azure/core-auth"; import { + AnalyzeTextOptions, AnalyzeTextResult, - ImageData, + AnalyzeImageOptions, AnalyzeImageResult, TextBlocklist, - TextBlockItemInfo, + AddOrUpdateBlockItemsOptions, AddOrUpdateBlockItemsResult, TextBlockItem, + RemoveBlockItemsOptions, PagedTextBlocklist, PagedTextBlockItem, } from "./models/models.js"; @@ -57,18 +59,18 @@ export class ContentSafetyClient { /** A sync API for harmful content analysis for text. Currently, we support four categories: Hate, SelfHarm, Sexual, Violence. */ analyzeText( - text: string, + body: AnalyzeTextOptions, options: AnalyzeTextRequestOptions = { requestOptions: {} } ): Promise { - return analyzeText(this._client, text, options); + return analyzeText(this._client, body, options); } /** A sync API for harmful content analysis for image. Currently, we support four categories: Hate, SelfHarm, Sexual, Violence. */ analyzeImage( - image: ImageData, + body: AnalyzeImageOptions, options: AnalyzeImageRequestOptions = { requestOptions: {} } ): Promise { - return analyzeImage(this._client, image, options); + return analyzeImage(this._client, body, options); } /** Returns text blocklist details. */ @@ -82,9 +84,15 @@ export class ContentSafetyClient { /** Updates a text blocklist, if blocklistName does not exist, create a new blocklist. */ createOrUpdateTextBlocklist( blocklistName: string, + resource: TextBlocklist, options: CreateOrUpdateTextBlocklistOptions = { requestOptions: {} } ): Promise { - return createOrUpdateTextBlocklist(this._client, blocklistName, options); + return createOrUpdateTextBlocklist( + this._client, + blocklistName, + resource, + options + ); } /** Deletes a text blocklist. */ @@ -104,25 +112,20 @@ export class ContentSafetyClient { /** Add or update blockItems to a text blocklist. You can add or update at most 100 BlockItems in one request. */ addOrUpdateBlockItems( - blockItems: TextBlockItemInfo[], blocklistName: string, + body: AddOrUpdateBlockItemsOptions, options: AddOrUpdateBlockItemsRequestOptions = { requestOptions: {} } ): Promise { - return addOrUpdateBlockItems( - this._client, - blockItems, - blocklistName, - options - ); + return addOrUpdateBlockItems(this._client, blocklistName, body, options); } /** Remove blockItems from a text blocklist. You can remove at most 100 BlockItems in one request. */ removeBlockItems( - blockItemIds: string[], blocklistName: string, + body: RemoveBlockItemsOptions, options: RemoveBlockItemsRequestOptions = { requestOptions: {} } ): Promise { - return removeBlockItems(this._client, blockItemIds, blocklistName, options); + return removeBlockItems(this._client, blocklistName, body, options); } /** Get blockItem By blockItemId from a text blocklist. */ diff --git a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/api/operations.ts b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/api/operations.ts index 45bf0addde..790eb35f95 100644 --- a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/api/operations.ts +++ b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/api/operations.ts @@ -2,13 +2,15 @@ // Licensed under the MIT license. import { + AnalyzeTextOptions, AnalyzeTextResult, - ImageData, + AnalyzeImageOptions, AnalyzeImageResult, TextBlocklist, - TextBlockItemInfo, + AddOrUpdateBlockItemsOptions, AddOrUpdateBlockItemsResult, TextBlockItem, + RemoveBlockItemsOptions, PagedTextBlocklist, PagedTextBlockItem, } from "../models/models.js"; @@ -57,7 +59,7 @@ import { export function _analyzeTextSend( context: Client, - text: string, + body: AnalyzeTextOptions, options: AnalyzeTextRequestOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -65,11 +67,11 @@ export function _analyzeTextSend( .post({ ...operationOptionsToRequestParameters(options), body: { - text: text, - categories: options?.categories, - blocklistNames: options?.blocklistNames, - breakByBlocklists: options?.breakByBlocklists, - outputType: options?.outputType, + text: body["text"], + categories: body["categories"], + blocklistNames: body["blocklistNames"], + breakByBlocklists: body["breakByBlocklists"], + outputType: body["outputType"], }, }); } @@ -99,16 +101,16 @@ export async function _analyzeTextDeserialize( /** A sync API for harmful content analysis for text. Currently, we support four categories: Hate, SelfHarm, Sexual, Violence. */ export async function analyzeText( context: Client, - text: string, + body: AnalyzeTextOptions, options: AnalyzeTextRequestOptions = { requestOptions: {} } ): Promise { - const result = await _analyzeTextSend(context, text, options); + const result = await _analyzeTextSend(context, body, options); return _analyzeTextDeserialize(result); } export function _analyzeImageSend( context: Client, - image: ImageData, + body: AnalyzeImageOptions, options: AnalyzeImageRequestOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -118,13 +120,13 @@ export function _analyzeImageSend( body: { image: { content: - image["content"] !== undefined - ? uint8ArrayToString(image["content"], "base64") + body.image["content"] !== undefined + ? uint8ArrayToString(body.image["content"], "base64") : undefined, - blobUrl: image["blobUrl"], + blobUrl: body.image["blobUrl"], }, - categories: options?.categories, - outputType: options?.outputType, + categories: body["categories"], + outputType: body["outputType"], }, }); } @@ -147,10 +149,10 @@ export async function _analyzeImageDeserialize( /** A sync API for harmful content analysis for image. Currently, we support four categories: Hate, SelfHarm, Sexual, Violence. */ export async function analyzeImage( context: Client, - image: ImageData, + body: AnalyzeImageOptions, options: AnalyzeImageRequestOptions = { requestOptions: {} } ): Promise { - const result = await _analyzeImageSend(context, image, options); + const result = await _analyzeImageSend(context, body, options); return _analyzeImageDeserialize(result); } @@ -192,6 +194,7 @@ export async function getTextBlocklist( export function _createOrUpdateTextBlocklistSend( context: Client, blocklistName: string, + resource: TextBlocklist, options: CreateOrUpdateTextBlocklistOptions = { requestOptions: {} } ): StreamableMethod< | CreateOrUpdateTextBlocklist200Response @@ -204,7 +207,7 @@ export function _createOrUpdateTextBlocklistSend( ...operationOptionsToRequestParameters(options), contentType: (options.contentType as any) ?? "application/merge-patch+json", - body: { description: options?.description }, + body: { description: resource["description"] }, }); } @@ -228,11 +231,13 @@ export async function _createOrUpdateTextBlocklistDeserialize( export async function createOrUpdateTextBlocklist( context: Client, blocklistName: string, + resource: TextBlocklist, options: CreateOrUpdateTextBlocklistOptions = { requestOptions: {} } ): Promise { const result = await _createOrUpdateTextBlocklistSend( context, blocklistName, + resource, options ); return _createOrUpdateTextBlocklistDeserialize(result); @@ -312,8 +317,8 @@ export async function listTextBlocklists( export function _addOrUpdateBlockItemsSend( context: Client, - blockItems: TextBlockItemInfo[], blocklistName: string, + body: AddOrUpdateBlockItemsOptions, options: AddOrUpdateBlockItemsRequestOptions = { requestOptions: {} } ): StreamableMethod< AddOrUpdateBlockItems200Response | AddOrUpdateBlockItemsDefaultResponse @@ -326,7 +331,7 @@ export function _addOrUpdateBlockItemsSend( .post({ ...operationOptionsToRequestParameters(options), body: { - blockItems: (blockItems ?? []).map((p) => ({ + blockItems: (body["blockItems"] ?? []).map((p) => ({ description: p["description"], text: p["text"], })), @@ -355,14 +360,14 @@ export async function _addOrUpdateBlockItemsDeserialize( /** Add or update blockItems to a text blocklist. You can add or update at most 100 BlockItems in one request. */ export async function addOrUpdateBlockItems( context: Client, - blockItems: TextBlockItemInfo[], blocklistName: string, + body: AddOrUpdateBlockItemsOptions, options: AddOrUpdateBlockItemsRequestOptions = { requestOptions: {} } ): Promise { const result = await _addOrUpdateBlockItemsSend( context, - blockItems, blocklistName, + body, options ); return _addOrUpdateBlockItemsDeserialize(result); @@ -370,8 +375,8 @@ export async function addOrUpdateBlockItems( export function _removeBlockItemsSend( context: Client, - blockItemIds: string[], blocklistName: string, + body: RemoveBlockItemsOptions, options: RemoveBlockItemsRequestOptions = { requestOptions: {} } ): StreamableMethod< RemoveBlockItems204Response | RemoveBlockItemsDefaultResponse @@ -380,7 +385,7 @@ export function _removeBlockItemsSend( .path("/text/blocklists/{blocklistName}:removeBlockItems", blocklistName) .post({ ...operationOptionsToRequestParameters(options), - body: { blockItemIds: blockItemIds }, + body: { blockItemIds: body["blockItemIds"] }, }); } @@ -397,14 +402,14 @@ export async function _removeBlockItemsDeserialize( /** Remove blockItems from a text blocklist. You can remove at most 100 BlockItems in one request. */ export async function removeBlockItems( context: Client, - blockItemIds: string[], blocklistName: string, + body: RemoveBlockItemsOptions, options: RemoveBlockItemsRequestOptions = { requestOptions: {} } ): Promise { const result = await _removeBlockItemsSend( context, - blockItemIds, blocklistName, + body, options ); return _removeBlockItemsDeserialize(result); diff --git a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/index.ts b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/index.ts index b88674e51a..08fdd88800 100644 --- a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/index.ts +++ b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/index.ts @@ -6,20 +6,24 @@ export { ContentSafetyClientOptions, } from "./ContentSafetyClient.js"; export { + AnalyzeTextOptions, TextCategory, AnalyzeTextOutputType, AnalyzeTextResult, TextBlocklistMatchResult, TextAnalyzeSeverityResult, + AnalyzeImageOptions, ImageData, ImageCategory, AnalyzeImageOutputType, AnalyzeImageResult, ImageAnalyzeSeverityResult, TextBlocklist, + AddOrUpdateBlockItemsOptions, TextBlockItemInfo, AddOrUpdateBlockItemsResult, TextBlockItem, + RemoveBlockItemsOptions, PagedTextBlocklist, PagedTextBlockItem, AnalyzeTextRequestOptions, diff --git a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/index.ts b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/index.ts index c5627b47ac..280a85b61f 100644 --- a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/index.ts +++ b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/index.ts @@ -2,20 +2,24 @@ // Licensed under the MIT license. export { + AnalyzeTextOptions, TextCategory, AnalyzeTextOutputType, AnalyzeTextResult, TextBlocklistMatchResult, TextAnalyzeSeverityResult, + AnalyzeImageOptions, ImageData, ImageCategory, AnalyzeImageOutputType, AnalyzeImageResult, ImageAnalyzeSeverityResult, TextBlocklist, + AddOrUpdateBlockItemsOptions, TextBlockItemInfo, AddOrUpdateBlockItemsResult, TextBlockItem, + RemoveBlockItemsOptions, PagedTextBlocklist, PagedTextBlockItem, } from "./models.js"; diff --git a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/models.ts b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/models.ts index 66fd6b8b05..83befbaf53 100644 --- a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/models.ts +++ b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/models.ts @@ -1,6 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +/** The analysis request of the text. */ +export interface AnalyzeTextOptions { + /** The text needs to be scanned. We support at most 10k Unicode characters (unicode code points) in text of one request. */ + text: string; + /** The categories will be analyzed. If not assigned, a default set of the categories' analysis results will be returned. */ + categories?: TextCategory[]; + /** The names of blocklists. */ + blocklistNames?: string[]; + /** When set to true, further analyses of harmful content will not be performed in cases where blocklists are hit. When set to false, all analyses of harmful content will be performed, whether or not blocklists are hit. */ + breakByBlocklists?: boolean; + /** The type of text analysis output. If not assigned, the default value is "FourLevels". */ + outputType?: AnalyzeTextOutputType; +} + /** Text analyze category */ /** "Hate", "SelfHarm", "Sexual", "Violence" */ export type TextCategory = string; @@ -34,6 +48,16 @@ export interface TextAnalyzeSeverityResult { severity?: number; } +/** The analysis request of the image. */ +export interface AnalyzeImageOptions { + /** The image needs to be analyzed. */ + image: ImageData; + /** The categories will be analyzed. If not assigned, a default set of the categories' analysis results will be returned. */ + categories?: ImageCategory[]; + /** The type of image analysis output. If not assigned, the default value is "FourLevels". */ + outputType?: AnalyzeImageOutputType; +} + /** The content or blob url of image, could be base64 encoding bytes or blob url. You can choose only one of them. If both are given, the request will be refused. The maximum size of image is 2048 pixels * 2048 pixels, no larger than 4MB at the same time. The minimum size of image is 50 pixels * 50 pixels. */ export interface ImageData { /** Base64 encoding of image. */ @@ -71,6 +95,12 @@ export interface TextBlocklist { description?: string; } +/** The request of adding blockItems to text blocklist. */ +export interface AddOrUpdateBlockItemsOptions { + /** Array of blockItemInfo to add. */ + blockItems: TextBlockItemInfo[]; +} + /** Block item info in text blocklist. */ export interface TextBlockItemInfo { /** Block item description. */ @@ -95,6 +125,12 @@ export interface TextBlockItem { text: string; } +/** The request of removing blockItems from text blocklist. */ +export interface RemoveBlockItemsOptions { + /** Array of blockItemIds to remove. */ + blockItemIds: string[]; +} + /** Paged collection of TextBlocklist items */ export interface PagedTextBlocklist { /** The TextBlocklist items on this page */ diff --git a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/options.ts b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/options.ts index 1d09a11f7f..33f3f77bb7 100644 --- a/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/options.ts +++ b/packages/typespec-test/test/contentsafety_modular/generated/typespec-ts/src/models/options.ts @@ -2,36 +2,14 @@ // Licensed under the MIT license. import { OperationOptions } from "@azure-rest/core-client"; -import { - TextCategory, - AnalyzeTextOutputType, - ImageCategory, - AnalyzeImageOutputType, -} from "./models.js"; - -export interface AnalyzeTextRequestOptions extends OperationOptions { - /** The categories will be analyzed. If not assigned, a default set of the categories' analysis results will be returned. */ - categories?: TextCategory[]; - /** The names of blocklists. */ - blocklistNames?: string[]; - /** When set to true, further analyses of harmful content will not be performed in cases where blocklists are hit. When set to false, all analyses of harmful content will be performed, whether or not blocklists are hit. */ - breakByBlocklists?: boolean; - /** The type of text analysis output. If not assigned, the default value is "FourLevels". */ - outputType?: AnalyzeTextOutputType; -} -export interface AnalyzeImageRequestOptions extends OperationOptions { - /** The categories will be analyzed. If not assigned, a default set of the categories' analysis results will be returned. */ - categories?: ImageCategory[]; - /** The type of image analysis output. If not assigned, the default value is "FourLevels". */ - outputType?: AnalyzeImageOutputType; -} +export interface AnalyzeTextRequestOptions extends OperationOptions {} + +export interface AnalyzeImageRequestOptions extends OperationOptions {} export interface GetTextBlocklistOptions extends OperationOptions {} export interface CreateOrUpdateTextBlocklistOptions extends OperationOptions { - /** Text blocklist description. */ - description?: string; /** This request has a JSON Merge Patch body. */ contentType?: string; } diff --git a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/review/eventgrid.api.md b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/review/eventgrid.api.md index d19ff0ea94..a0e862e053 100644 --- a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/review/eventgrid.api.md +++ b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/review/eventgrid.api.md @@ -13,6 +13,11 @@ export interface AcknowledgeCloudEventsOptions extends OperationOptions { contentType?: string; } +// @public +export interface AcknowledgeOptions { + lockTokens: string[]; +} + // @public export interface AcknowledgeResult { failedLockTokens: FailedLockToken[]; @@ -42,12 +47,12 @@ export interface CloudEvent { // @public (undocumented) export class EventGridClient { constructor(endpoint: string, credential: KeyCredential, options?: EventGridClientOptions); - acknowledgeCloudEvents(lockTokens: string[], topicName: string, eventSubscriptionName: string, options?: AcknowledgeCloudEventsOptions): Promise; - publishCloudEvent(event: CloudEvent, topicName: string, options?: PublishCloudEventOptions): Promise>; - publishCloudEvents(events: CloudEvent[], topicName: string, options?: PublishCloudEventsOptions): Promise>; + acknowledgeCloudEvents(topicName: string, eventSubscriptionName: string, lockTokens: AcknowledgeOptions, options?: AcknowledgeCloudEventsOptions): Promise; + publishCloudEvent(topicName: string, event: CloudEvent, options?: PublishCloudEventOptions): Promise>; + publishCloudEvents(topicName: string, events: CloudEvent[], options?: PublishCloudEventsOptions): Promise>; receiveCloudEvents(topicName: string, eventSubscriptionName: string, options?: ReceiveCloudEventsOptions): Promise; - rejectCloudEvents(lockTokens: string[], topicName: string, eventSubscriptionName: string, options?: RejectCloudEventsOptions): Promise; - releaseCloudEvents(lockTokens: string[], topicName: string, eventSubscriptionName: string, options?: ReleaseCloudEventsOptions): Promise; + rejectCloudEvents(topicName: string, eventSubscriptionName: string, lockTokens: RejectOptions, options?: RejectCloudEventsOptions): Promise; + releaseCloudEvents(topicName: string, eventSubscriptionName: string, lockTokens: ReleaseOptions, options?: ReleaseCloudEventsOptions): Promise; } // @public (undocumented) @@ -93,6 +98,11 @@ export interface RejectCloudEventsOptions extends OperationOptions { contentType?: string; } +// @public +export interface RejectOptions { + lockTokens: string[]; +} + // @public export interface RejectResult { failedLockTokens: FailedLockToken[]; @@ -104,6 +114,11 @@ export interface ReleaseCloudEventsOptions extends OperationOptions { contentType?: string; } +// @public +export interface ReleaseOptions { + lockTokens: string[]; +} + // @public export interface ReleaseResult { failedLockTokens: FailedLockToken[]; diff --git a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/EventGridClient.ts b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/EventGridClient.ts index 37d7610efe..73d77132e3 100644 --- a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/EventGridClient.ts +++ b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/EventGridClient.ts @@ -5,8 +5,11 @@ import { KeyCredential } from "@azure/core-auth"; import { CloudEvent, ReceiveResult, + AcknowledgeOptions, AcknowledgeResult, + ReleaseOptions, ReleaseResult, + RejectOptions, RejectResult, } from "./models/models.js"; import { @@ -45,20 +48,20 @@ export class EventGridClient { /** Publish Single Cloud Event to namespace topic. In case of success, the server responds with an HTTP 200 status code with an empty JSON object in response. Otherwise, the server can return various error codes. For example, 401: which indicates authorization failure, 403: which indicates quota exceeded or message is too large, 410: which indicates that specific topic is not found, 400: for bad request, and 500: for internal server error. */ publishCloudEvent( - event: CloudEvent, topicName: string, + event: CloudEvent, options: PublishCloudEventOptions = { requestOptions: {} } ): Promise> { - return publishCloudEvent(this._client, event, topicName, options); + return publishCloudEvent(this._client, topicName, event, options); } /** Publish Batch Cloud Event to namespace topic. In case of success, the server responds with an HTTP 200 status code with an empty JSON object in response. Otherwise, the server can return various error codes. For example, 401: which indicates authorization failure, 403: which indicates quota exceeded or message is too large, 410: which indicates that specific topic is not found, 400: for bad request, and 500: for internal server error. */ publishCloudEvents( - events: CloudEvent[], topicName: string, + events: CloudEvent[], options: PublishCloudEventsOptions = { requestOptions: {} } ): Promise> { - return publishCloudEvents(this._client, events, topicName, options); + return publishCloudEvents(this._client, topicName, events, options); } /** Receive Batch of Cloud Events from the Event Subscription. */ @@ -77,48 +80,48 @@ export class EventGridClient { /** Acknowledge batch of Cloud Events. The server responds with an HTTP 200 status code if at least one event is successfully acknowledged. The response body will include the set of successfully acknowledged lockTokens, along with other failed lockTokens with their corresponding error information. Successfully acknowledged events will no longer be available to any consumer. */ acknowledgeCloudEvents( - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: AcknowledgeOptions, options: AcknowledgeCloudEventsOptions = { requestOptions: {} } ): Promise { return acknowledgeCloudEvents( this._client, - lockTokens, topicName, eventSubscriptionName, + lockTokens, options ); } /** Release batch of Cloud Events. The server responds with an HTTP 200 status code if at least one event is successfully released. The response body will include the set of successfully released lockTokens, along with other failed lockTokens with their corresponding error information. */ releaseCloudEvents( - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: ReleaseOptions, options: ReleaseCloudEventsOptions = { requestOptions: {} } ): Promise { return releaseCloudEvents( this._client, - lockTokens, topicName, eventSubscriptionName, + lockTokens, options ); } /** Reject batch of Cloud Events. */ rejectCloudEvents( - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: RejectOptions, options: RejectCloudEventsOptions = { requestOptions: {} } ): Promise { return rejectCloudEvents( this._client, - lockTokens, topicName, eventSubscriptionName, + lockTokens, options ); } diff --git a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/api/operations.ts b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/api/operations.ts index 9354b21e20..a65822478b 100644 --- a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/api/operations.ts +++ b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/api/operations.ts @@ -4,8 +4,11 @@ import { CloudEvent, ReceiveResult, + AcknowledgeOptions, AcknowledgeResult, + ReleaseOptions, ReleaseResult, + RejectOptions, RejectResult, } from "../models/models.js"; import { @@ -40,8 +43,8 @@ import { export function _publishCloudEventSend( context: Client, - event: CloudEvent, topicName: string, + event: CloudEvent, options: PublishCloudEventOptions = { requestOptions: {} } ): StreamableMethod< PublishCloudEvent200Response | PublishCloudEventDefaultResponse @@ -86,14 +89,14 @@ export async function _publishCloudEventDeserialize( /** Publish Single Cloud Event to namespace topic. In case of success, the server responds with an HTTP 200 status code with an empty JSON object in response. Otherwise, the server can return various error codes. For example, 401: which indicates authorization failure, 403: which indicates quota exceeded or message is too large, 410: which indicates that specific topic is not found, 400: for bad request, and 500: for internal server error. */ export async function publishCloudEvent( context: Client, - event: CloudEvent, topicName: string, + event: CloudEvent, options: PublishCloudEventOptions = { requestOptions: {} } ): Promise> { const result = await _publishCloudEventSend( context, - event, topicName, + event, options ); return _publishCloudEventDeserialize(result); @@ -101,8 +104,8 @@ export async function publishCloudEvent( export function _publishCloudEventsSend( context: Client, - events: CloudEvent[], topicName: string, + events: CloudEvent[], options: PublishCloudEventsOptions = { requestOptions: {} } ): StreamableMethod< PublishCloudEvents200Response | PublishCloudEventsDefaultResponse @@ -145,14 +148,14 @@ export async function _publishCloudEventsDeserialize( /** Publish Batch Cloud Event to namespace topic. In case of success, the server responds with an HTTP 200 status code with an empty JSON object in response. Otherwise, the server can return various error codes. For example, 401: which indicates authorization failure, 403: which indicates quota exceeded or message is too large, 410: which indicates that specific topic is not found, 400: for bad request, and 500: for internal server error. */ export async function publishCloudEvents( context: Client, - events: CloudEvent[], topicName: string, + events: CloudEvent[], options: PublishCloudEventsOptions = { requestOptions: {} } ): Promise> { const result = await _publishCloudEventsSend( context, - events, topicName, + events, options ); return _publishCloudEventsDeserialize(result); @@ -232,9 +235,9 @@ export async function receiveCloudEvents( export function _acknowledgeCloudEventsSend( context: Client, - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: AcknowledgeOptions, options: AcknowledgeCloudEventsOptions = { requestOptions: {} } ): StreamableMethod< AcknowledgeCloudEvents200Response | AcknowledgeCloudEventsDefaultResponse @@ -249,7 +252,7 @@ export function _acknowledgeCloudEventsSend( ...operationOptionsToRequestParameters(options), contentType: (options.contentType as any) ?? "application/json; charset=utf-8", - body: { lockTokens: lockTokens }, + body: { lockTokens: lockTokens["lockTokens"] }, }); } @@ -275,16 +278,16 @@ export async function _acknowledgeCloudEventsDeserialize( /** Acknowledge batch of Cloud Events. The server responds with an HTTP 200 status code if at least one event is successfully acknowledged. The response body will include the set of successfully acknowledged lockTokens, along with other failed lockTokens with their corresponding error information. Successfully acknowledged events will no longer be available to any consumer. */ export async function acknowledgeCloudEvents( context: Client, - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: AcknowledgeOptions, options: AcknowledgeCloudEventsOptions = { requestOptions: {} } ): Promise { const result = await _acknowledgeCloudEventsSend( context, - lockTokens, topicName, eventSubscriptionName, + lockTokens, options ); return _acknowledgeCloudEventsDeserialize(result); @@ -292,9 +295,9 @@ export async function acknowledgeCloudEvents( export function _releaseCloudEventsSend( context: Client, - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: ReleaseOptions, options: ReleaseCloudEventsOptions = { requestOptions: {} } ): StreamableMethod< ReleaseCloudEvents200Response | ReleaseCloudEventsDefaultResponse @@ -309,7 +312,7 @@ export function _releaseCloudEventsSend( ...operationOptionsToRequestParameters(options), contentType: (options.contentType as any) ?? "application/json; charset=utf-8", - body: { lockTokens: lockTokens }, + body: { lockTokens: lockTokens["lockTokens"] }, }); } @@ -333,16 +336,16 @@ export async function _releaseCloudEventsDeserialize( /** Release batch of Cloud Events. The server responds with an HTTP 200 status code if at least one event is successfully released. The response body will include the set of successfully released lockTokens, along with other failed lockTokens with their corresponding error information. */ export async function releaseCloudEvents( context: Client, - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: ReleaseOptions, options: ReleaseCloudEventsOptions = { requestOptions: {} } ): Promise { const result = await _releaseCloudEventsSend( context, - lockTokens, topicName, eventSubscriptionName, + lockTokens, options ); return _releaseCloudEventsDeserialize(result); @@ -350,9 +353,9 @@ export async function releaseCloudEvents( export function _rejectCloudEventsSend( context: Client, - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: RejectOptions, options: RejectCloudEventsOptions = { requestOptions: {} } ): StreamableMethod< RejectCloudEvents200Response | RejectCloudEventsDefaultResponse @@ -367,7 +370,7 @@ export function _rejectCloudEventsSend( ...operationOptionsToRequestParameters(options), contentType: (options.contentType as any) ?? "application/json; charset=utf-8", - body: { lockTokens: lockTokens }, + body: { lockTokens: lockTokens["lockTokens"] }, }); } @@ -391,16 +394,16 @@ export async function _rejectCloudEventsDeserialize( /** Reject batch of Cloud Events. */ export async function rejectCloudEvents( context: Client, - lockTokens: string[], topicName: string, eventSubscriptionName: string, + lockTokens: RejectOptions, options: RejectCloudEventsOptions = { requestOptions: {} } ): Promise { const result = await _rejectCloudEventsSend( context, - lockTokens, topicName, eventSubscriptionName, + lockTokens, options ); return _rejectCloudEventsDeserialize(result); diff --git a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/index.ts b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/index.ts index f2fd2dccf8..26fa3b15f5 100644 --- a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/index.ts +++ b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/index.ts @@ -7,9 +7,12 @@ export { ReceiveResult, ReceiveDetails, BrokerProperties, + AcknowledgeOptions, AcknowledgeResult, FailedLockToken, + ReleaseOptions, ReleaseResult, + RejectOptions, RejectResult, PublishCloudEventOptions, PublishCloudEventsOptions, diff --git a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/models/index.ts b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/models/index.ts index 460809847e..df8ef8378d 100644 --- a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/models/index.ts +++ b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/models/index.ts @@ -6,9 +6,12 @@ export { ReceiveResult, ReceiveDetails, BrokerProperties, + AcknowledgeOptions, AcknowledgeResult, FailedLockToken, + ReleaseOptions, ReleaseResult, + RejectOptions, RejectResult, } from "./models.js"; export { diff --git a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/models/models.ts b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/models/models.ts index b16e8d6069..edf13ea46a 100644 --- a/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/models/models.ts +++ b/packages/typespec-test/test/eventgrid_modular/generated/typespec-ts/src/models/models.ts @@ -47,6 +47,12 @@ export interface BrokerProperties { deliveryCount: number; } +/** Array of lock token strings for the corresponding received Cloud Events to be acknowledged. */ +export interface AcknowledgeOptions { + /** String array of lock tokens. */ + lockTokens: string[]; +} + /** The result of the Acknowledge operation. */ export interface AcknowledgeResult { /** Array of LockToken values for failed cloud events. Each LockToken includes the lock token value along with the related error information (namely, the error code and description). */ @@ -65,6 +71,12 @@ export interface FailedLockToken { errorDescription: string; } +/** Array of lock token strings for the corresponding received Cloud Events to be released. */ +export interface ReleaseOptions { + /** String array of lock tokens. */ + lockTokens: string[]; +} + /** The result of the Release operation. */ export interface ReleaseResult { /** Array of LockToken values for failed cloud events. Each LockToken includes the lock token value along with the related error information (namely, the error code and description). */ @@ -73,6 +85,12 @@ export interface ReleaseResult { succeededLockTokens: string[]; } +/** Array of lock token strings for the corresponding received Cloud Events to be rejected. */ +export interface RejectOptions { + /** String array of lock tokens. */ + lockTokens: string[]; +} + /** The result of the Reject operation. */ export interface RejectResult { /** Array of LockToken values for failed cloud events. Each LockToken includes the lock token value along with the related error information (namely, the error code and description). */ diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/review/load-testing.api.md b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/review/load-testing.api.md index 98908c7c9e..71ae2c031d 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/review/load-testing.api.md +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/review/load-testing.api.md @@ -36,45 +36,18 @@ export type CertificateType = string; export interface CreateOrUpdateAppComponentsOptions extends OperationOptions { // (undocumented) contentType?: string; - createdBy?: string; - createdDateTime?: string; - lastModifiedBy?: string; - lastModifiedDateTime?: string; - testId?: string; } // @public (undocumented) export interface CreateOrUpdateServerMetricsConfigOptions extends OperationOptions { // (undocumented) contentType?: string; - createdBy?: string; - createdDateTime?: string; - lastModifiedBy?: string; - lastModifiedDateTime?: string; - metrics?: Record; - testId?: string; } // @public (undocumented) export interface CreateOrUpdateTestOptions extends OperationOptions { - certificate?: CertificateMetadata; // (undocumented) contentType?: string; - createdBy?: string; - createdDateTime?: string; - description?: string; - displayName?: string; - environmentVariables?: Record; - inputArtifacts?: TestInputArtifacts; - keyvaultReferenceIdentityId?: string; - keyvaultReferenceIdentityType?: string; - lastModifiedBy?: string; - lastModifiedDateTime?: string; - loadTestConfiguration?: LoadTestConfiguration; - passFailCriteria?: PassFailCriteria; - secrets?: Record; - subnetId?: string; - testId?: string; } // @public (undocumented) @@ -174,7 +147,6 @@ export interface ListMetricNamespacesOptions extends OperationOptions { // @public (undocumented) export interface ListMetricsOptions extends OperationOptions { aggregation?: string; - filters?: LoadTestRunClientDimensionFilter[]; interval?: LoadTestRunClientInterval; metricName?: string; metricNamespace?: string; @@ -208,9 +180,9 @@ export interface ListTestsOptions extends OperationOptions { // @public (undocumented) export class LoadTestAdministrationClient { constructor(endpoint: string, credential: TokenCredential, options?: LoadTestAdministrationClientOptions); - createOrUpdateAppComponents(components: Record, testId: string, options?: CreateOrUpdateAppComponentsOptions): Promise; - createOrUpdateServerMetricsConfig(testId: string, options?: CreateOrUpdateServerMetricsConfigOptions): Promise; - createOrUpdateTest(testId: string, options?: CreateOrUpdateTestOptions): Promise; + createOrUpdateAppComponents(testId: string, body: TestAppComponents, options?: CreateOrUpdateAppComponentsOptions): Promise; + createOrUpdateServerMetricsConfig(testId: string, body: TestServerMetricConfig, options?: CreateOrUpdateServerMetricsConfigOptions): Promise; + createOrUpdateTest(testId: string, body: Test, options?: CreateOrUpdateTestOptions): Promise; deleteTest(testId: string, options?: DeleteTestOptions): Promise; deleteTestFile(testId: string, fileName: string, options?: DeleteTestFileOptions): Promise; getAppComponents(testId: string, options?: GetAppComponentsOptions): Promise; @@ -219,7 +191,7 @@ export class LoadTestAdministrationClient { getTestFile(testId: string, fileName: string, options?: GetTestFileOptions): Promise; listTestFiles(testId: string, options?: ListTestFilesOptions): Promise; listTests(options?: ListTestsOptions): Promise; - uploadTestFile(body: Uint8Array, testId: string, fileName: string, options?: UploadTestFileOptions): Promise; + uploadTestFile(testId: string, fileName: string, body: Uint8Array, options?: UploadTestFileOptions): Promise; } // @public (undocumented) @@ -238,9 +210,9 @@ export interface LoadTestConfiguration { export class LoadTestRunClient { constructor(endpoint: string, credential: TokenCredential, options?: LoadTestRunClientOptions); // Warning: (ae-forgotten-export) The symbol "TestRunAppComponents" needs to be exported by the entry point index.d.ts - createOrUpdateAppComponents(components: Record, testRunId: string, options?: LoadTestRunClientCreateOrUpdateAppComponentsOptions): Promise; + createOrUpdateAppComponents(testRunId: string, body: TestRunAppComponents, options?: LoadTestRunClientCreateOrUpdateAppComponentsOptions): Promise; // Warning: (ae-forgotten-export) The symbol "TestRunServerMetricConfig" needs to be exported by the entry point index.d.ts - createOrUpdateServerMetricsConfig(testRunId: string, options?: LoadTestRunClientCreateOrUpdateServerMetricsConfigOptions): Promise; + createOrUpdateServerMetricsConfig(testRunId: string, body: TestRunServerMetricConfig, options?: LoadTestRunClientCreateOrUpdateServerMetricsConfigOptions): Promise; deleteTestRun(testRunId: string, options?: DeleteTestRunOptions): Promise; getAppComponents(testRunId: string, options?: LoadTestRunClientGetAppComponentsOptions): Promise; getServerMetricsConfig(testRunId: string, options?: LoadTestRunClientGetServerMetricsConfigOptions): Promise; @@ -252,12 +224,13 @@ export class LoadTestRunClient { listMetricDimensionValues(testRunId: string, name: string, metricNamespace: string, options?: ListMetricDimensionValuesOptions): Promise; // Warning: (ae-forgotten-export) The symbol "MetricNamespaceCollection" needs to be exported by the entry point index.d.ts listMetricNamespaces(testRunId: string, options?: ListMetricNamespacesOptions): Promise; + // Warning: (ae-forgotten-export) The symbol "MetricRequestPayload" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "PagedTimeSeriesElement" needs to be exported by the entry point index.d.ts - listMetrics(testRunId: string, options?: ListMetricsOptions): Promise; + listMetrics(testRunId: string, body: MetricRequestPayload, options?: ListMetricsOptions): Promise; // Warning: (ae-forgotten-export) The symbol "PagedTestRun" needs to be exported by the entry point index.d.ts listTestRuns(options?: ListTestRunsOptions): Promise; stopTestRun(testRunId: string, options?: StopTestRunOptions): Promise; - testRun(testRunId: string, options?: TestRunOptions): Promise; + testRun(testRunId: string, resource: LoadTestRunClientTestRun, options?: TestRunOptions): Promise; } // @public @@ -288,23 +261,12 @@ export type LoadTestRunClientCertificateType = string; export interface LoadTestRunClientCreateOrUpdateAppComponentsOptions extends OperationOptions { // (undocumented) contentType?: string; - createdBy?: string; - createdDateTime?: string; - lastModifiedBy?: string; - lastModifiedDateTime?: string; - testRunId?: string; } // @public (undocumented) export interface LoadTestRunClientCreateOrUpdateServerMetricsConfigOptions extends OperationOptions { // (undocumented) contentType?: string; - createdBy?: string; - createdDateTime?: string; - lastModifiedBy?: string; - lastModifiedDateTime?: string; - metrics?: Record; - testRunId?: string; } // @public @@ -780,32 +742,8 @@ export interface TestRunInputArtifacts { // @public (undocumented) export interface TestRunOptions extends OperationOptions { - certificate?: LoadTestRunClientCertificateMetadata; contentType?: string; - createdBy?: string; - createdDateTime?: string; - description?: string; - displayName?: string; - duration?: number; - endDateTime?: string; - environmentVariables?: Record; - errorDetails?: LoadTestRunClientErrorDetails[]; - executedDateTime?: string; - lastModifiedBy?: string; - lastModifiedDateTime?: string; - loadTestConfiguration?: LoadTestRunClientLoadTestConfiguration; oldTestRunId?: string; - passFailCriteria?: LoadTestRunClientPassFailCriteria; - portalUrl?: string; - secrets?: Record; - startDateTime?: string; - status?: LoadTestRunClientStatus; - subnetId?: string; - testArtifacts?: LoadTestRunClientTestRunArtifacts; - testId?: string; - testResult?: LoadTestRunClientPFTestResult; - testRunStatistics?: Record; - virtualUsers?: number; } // @public diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/LoadTestAdministrationClient.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/LoadTestAdministrationClient.ts index 4fea050495..adc667e9bd 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/LoadTestAdministrationClient.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/LoadTestAdministrationClient.ts @@ -6,7 +6,6 @@ import { Test, FileInfo, TestAppComponents, - AppComponent, TestServerMetricConfig, PagedFileInfo, PagedTest, @@ -59,31 +58,33 @@ export class LoadTestAdministrationClient { /** Create a new test or update an existing test. */ createOrUpdateTest( testId: string, + body: Test, options: CreateOrUpdateTestOptions = { requestOptions: {} } ): Promise { - return createOrUpdateTest(this._client, testId, options); + return createOrUpdateTest(this._client, testId, body, options); } /** Associate an app component (collection of azure resources) to a test */ createOrUpdateAppComponents( - components: Record, testId: string, + body: TestAppComponents, options: CreateOrUpdateAppComponentsOptions = { requestOptions: {} } ): Promise { - return createOrUpdateAppComponents( - this._client, - components, - testId, - options - ); + return createOrUpdateAppComponents(this._client, testId, body, options); } /** Configure server metrics for a test */ createOrUpdateServerMetricsConfig( testId: string, + body: TestServerMetricConfig, options: CreateOrUpdateServerMetricsConfigOptions = { requestOptions: {} } ): Promise { - return createOrUpdateServerMetricsConfig(this._client, testId, options); + return createOrUpdateServerMetricsConfig( + this._client, + testId, + body, + options + ); } /** Get associated app component (collection of azure resources) for the given test. */ @@ -143,12 +144,12 @@ export class LoadTestAdministrationClient { * should be provided in the request body as application/octet-stream. */ uploadTestFile( - body: Uint8Array, testId: string, fileName: string, + body: Uint8Array, options: UploadTestFileOptions = { requestOptions: {} } ): Promise { - return uploadTestFile(this._client, body, testId, fileName, options); + return uploadTestFile(this._client, testId, fileName, body, options); } /** Delete file by the file name for a test */ diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/api/operations.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/api/operations.ts index 1c1a4e0033..0bba83d2b6 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/api/operations.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/api/operations.ts @@ -5,7 +5,6 @@ import { Test, FileInfo, TestAppComponents, - AppComponent, TestServerMetricConfig, PagedFileInfo, PagedTest, @@ -63,6 +62,7 @@ import { export function _createOrUpdateTestSend( context: Client, testId: string, + body: Test, options: CreateOrUpdateTestOptions = { requestOptions: {} } ): StreamableMethod< | LoadTestAdministrationCreateOrUpdateTest200Response @@ -76,47 +76,51 @@ export function _createOrUpdateTestSend( contentType: (options.contentType as any) ?? "application/merge-patch+json", body: { - passFailCriteria: { - passFailMetrics: options?.passFailCriteria?.["passFailMetrics"], - }, - secrets: options?.secrets, - certificate: { - value: options?.certificate?.["value"], - type: options?.certificate?.["type"], - name: options?.certificate?.["name"], - }, - environmentVariables: options?.environmentVariables, - loadTestConfiguration: { - engineInstances: options?.loadTestConfiguration?.["engineInstances"], - splitAllCSVs: options?.loadTestConfiguration?.["splitAllCSVs"], - quickStartTest: options?.loadTestConfiguration?.["quickStartTest"], - optionalLoadTestConfig: !options?.loadTestConfiguration - ?.optionalLoadTestConfig - ? undefined - : { - endpointUrl: - options?.loadTestConfiguration?.optionalLoadTestConfig?.[ - "endpointUrl" - ], - virtualUsers: - options?.loadTestConfiguration?.optionalLoadTestConfig?.[ - "virtualUsers" - ], - rampUpTime: - options?.loadTestConfiguration?.optionalLoadTestConfig?.[ - "rampUpTime" - ], - duration: - options?.loadTestConfiguration?.optionalLoadTestConfig?.[ - "duration" - ], - }, - }, - description: options?.description, - displayName: options?.displayName, - subnetId: options?.subnetId, - keyvaultReferenceIdentityType: options?.keyvaultReferenceIdentityType, - keyvaultReferenceIdentityId: options?.keyvaultReferenceIdentityId, + passFailCriteria: !body.passFailCriteria + ? undefined + : { passFailMetrics: body.passFailCriteria?.["passFailMetrics"] }, + secrets: body["secrets"], + certificate: !body.certificate + ? undefined + : { + value: body.certificate?.["value"], + type: body.certificate?.["type"], + name: body.certificate?.["name"], + }, + environmentVariables: body["environmentVariables"], + loadTestConfiguration: !body.loadTestConfiguration + ? undefined + : { + engineInstances: body.loadTestConfiguration?.["engineInstances"], + splitAllCSVs: body.loadTestConfiguration?.["splitAllCSVs"], + quickStartTest: body.loadTestConfiguration?.["quickStartTest"], + optionalLoadTestConfig: !body.loadTestConfiguration + ?.optionalLoadTestConfig + ? undefined + : { + endpointUrl: + body.loadTestConfiguration?.optionalLoadTestConfig?.[ + "endpointUrl" + ], + virtualUsers: + body.loadTestConfiguration?.optionalLoadTestConfig?.[ + "virtualUsers" + ], + rampUpTime: + body.loadTestConfiguration?.optionalLoadTestConfig?.[ + "rampUpTime" + ], + duration: + body.loadTestConfiguration?.optionalLoadTestConfig?.[ + "duration" + ], + }, + }, + description: body["description"], + displayName: body["displayName"], + subnetId: body["subnetId"], + keyvaultReferenceIdentityType: body["keyvaultReferenceIdentityType"], + keyvaultReferenceIdentityId: body["keyvaultReferenceIdentityId"], }, }); } @@ -295,16 +299,17 @@ export async function _createOrUpdateTestDeserialize( export async function createOrUpdateTest( context: Client, testId: string, + body: Test, options: CreateOrUpdateTestOptions = { requestOptions: {} } ): Promise { - const result = await _createOrUpdateTestSend(context, testId, options); + const result = await _createOrUpdateTestSend(context, testId, body, options); return _createOrUpdateTestDeserialize(result); } export function _createOrUpdateAppComponentsSend( context: Client, - components: Record, testId: string, + body: TestAppComponents, options: CreateOrUpdateAppComponentsOptions = { requestOptions: {} } ): StreamableMethod< | LoadTestAdministrationCreateOrUpdateAppComponents200Response @@ -317,7 +322,7 @@ export function _createOrUpdateAppComponentsSend( ...operationOptionsToRequestParameters(options), contentType: (options.contentType as any) ?? "application/merge-patch+json", - body: { components: components }, + body: { components: body["components"] }, }); } @@ -344,14 +349,14 @@ export async function _createOrUpdateAppComponentsDeserialize( /** Associate an app component (collection of azure resources) to a test */ export async function createOrUpdateAppComponents( context: Client, - components: Record, testId: string, + body: TestAppComponents, options: CreateOrUpdateAppComponentsOptions = { requestOptions: {} } ): Promise { const result = await _createOrUpdateAppComponentsSend( context, - components, testId, + body, options ); return _createOrUpdateAppComponentsDeserialize(result); @@ -360,6 +365,7 @@ export async function createOrUpdateAppComponents( export function _createOrUpdateServerMetricsConfigSend( context: Client, testId: string, + body: TestServerMetricConfig, options: CreateOrUpdateServerMetricsConfigOptions = { requestOptions: {} } ): StreamableMethod< | LoadTestAdministrationCreateOrUpdateServerMetricsConfig200Response @@ -372,7 +378,7 @@ export function _createOrUpdateServerMetricsConfigSend( ...operationOptionsToRequestParameters(options), contentType: (options.contentType as any) ?? "application/merge-patch+json", - body: { metrics: options?.metrics }, + body: { metrics: body["metrics"] }, }); } @@ -400,11 +406,13 @@ export async function _createOrUpdateServerMetricsConfigDeserialize( export async function createOrUpdateServerMetricsConfig( context: Client, testId: string, + body: TestServerMetricConfig, options: CreateOrUpdateServerMetricsConfigOptions = { requestOptions: {} } ): Promise { const result = await _createOrUpdateServerMetricsConfigSend( context, testId, + body, options ); return _createOrUpdateServerMetricsConfigDeserialize(result); @@ -957,9 +965,9 @@ export async function listTests( export function _uploadTestFileSend( context: Client, - body: Uint8Array, testId: string, fileName: string, + body: Uint8Array, options: UploadTestFileOptions = { requestOptions: {} } ): StreamableMethod< | LoadTestAdministrationUploadTestFile201Response @@ -1001,16 +1009,16 @@ export async function _uploadTestFileDeserialize( */ export async function uploadTestFile( context: Client, - body: Uint8Array, testId: string, fileName: string, + body: Uint8Array, options: UploadTestFileOptions = { requestOptions: {} } ): Promise { const result = await _uploadTestFileSend( context, - body, testId, fileName, + body, options ); return _uploadTestFileDeserialize(result); diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/models/options.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/models/options.ts index 5cb2891222..92f797e4dd 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/models/options.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestAdministration/models/options.ts @@ -2,90 +2,18 @@ // Licensed under the MIT license. import { OperationOptions } from "@azure-rest/core-client"; -import { - PassFailCriteria, - Secret, - CertificateMetadata, - LoadTestConfiguration, - TestInputArtifacts, - ResourceMetric, - FileType, -} from "./models.js"; +import { FileType } from "./models.js"; export interface CreateOrUpdateTestOptions extends OperationOptions { - /** Pass fail criteria for a test. */ - passFailCriteria?: PassFailCriteria; - /** - * Secrets can be stored in an Azure Key Vault or any other secret store. If the - * secret is stored in an Azure Key Vault, the value should be the secret - * identifier and the type should be AKV_SECRET_URI. If the secret is stored - * elsewhere, the secret value should be provided directly and the type should be - * SECRET_VALUE. - */ - secrets?: Record; - /** Certificates metadata */ - certificate?: CertificateMetadata; - /** Environment variables which are defined as a set of pairs. */ - environmentVariables?: Record; - /** The load test configuration. */ - loadTestConfiguration?: LoadTestConfiguration; - /** The input artifacts for the test. */ - inputArtifacts?: TestInputArtifacts; - /** Unique test name as identifier. */ - testId?: string; - /** The test description. */ - description?: string; - /** Display name of a test. */ - displayName?: string; - /** Subnet ID on which the load test instances should run. */ - subnetId?: string; - /** Type of the managed identity referencing the Key vault. */ - keyvaultReferenceIdentityType?: string; - /** Resource Id of the managed identity referencing the Key vault. */ - keyvaultReferenceIdentityId?: string; - /** The creation datetime(ISO 8601 literal format). */ - createdDateTime?: string; - /** The user that created. */ - createdBy?: string; - /** The last Modified datetime(ISO 8601 literal format). */ - lastModifiedDateTime?: string; - /** The user that last modified. */ - lastModifiedBy?: string; contentType?: string; } export interface CreateOrUpdateAppComponentsOptions extends OperationOptions { - /** Test identifier */ - testId?: string; - /** The creation datetime(ISO 8601 literal format). */ - createdDateTime?: string; - /** The user that created. */ - createdBy?: string; - /** The last Modified datetime(ISO 8601 literal format). */ - lastModifiedDateTime?: string; - /** The user that last modified. */ - lastModifiedBy?: string; contentType?: string; } export interface CreateOrUpdateServerMetricsConfigOptions extends OperationOptions { - /** Test identifier */ - testId?: string; - /** - * Azure resource metrics collection {metric id : metrics object} (Refer : - * https://docs.microsoft.com/en-us/rest/api/monitor/metric-definitions/list#metricdefinition - * for metric id). - */ - metrics?: Record; - /** The creation datetime(ISO 8601 literal format). */ - createdDateTime?: string; - /** The user that created. */ - createdBy?: string; - /** The last Modified datetime(ISO 8601 literal format). */ - lastModifiedDateTime?: string; - /** The user that last modified. */ - lastModifiedBy?: string; contentType?: string; } diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/LoadTestRunClient.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/LoadTestRunClient.ts index 5682157ae5..5037f9f120 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/LoadTestRunClient.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/LoadTestRunClient.ts @@ -4,12 +4,12 @@ import { TokenCredential } from "@azure/core-auth"; import { FileInfo, - AppComponent, TestRun, TestRunAppComponents, TestRunServerMetricConfig, MetricDefinitionCollection, MetricNamespaceCollection, + MetricRequestPayload, PagedTimeSeriesElement, PagedTestRun, PagedDimensionValueList, @@ -66,31 +66,33 @@ export class LoadTestRunClient { /** Create and start a new test run with the given name. */ testRun( testRunId: string, + resource: TestRun, options: TestRunOptions = { requestOptions: {} } ): Promise { - return testRun(this._client, testRunId, options); + return testRun(this._client, testRunId, resource, options); } /** Associate an app component (collection of azure resources) to a test run */ createOrUpdateAppComponents( - components: Record, testRunId: string, + body: TestRunAppComponents, options: CreateOrUpdateAppComponentsOptions = { requestOptions: {} } ): Promise { - return createOrUpdateAppComponents( - this._client, - components, - testRunId, - options - ); + return createOrUpdateAppComponents(this._client, testRunId, body, options); } /** Configure server metrics for a test run */ createOrUpdateServerMetricsConfig( testRunId: string, + body: TestRunServerMetricConfig, options: CreateOrUpdateServerMetricsConfigOptions = { requestOptions: {} } ): Promise { - return createOrUpdateServerMetricsConfig(this._client, testRunId, options); + return createOrUpdateServerMetricsConfig( + this._client, + testRunId, + body, + options + ); } /** Delete a test run by its name. */ @@ -172,9 +174,10 @@ export class LoadTestRunClient { /** List the metric values for a load test run. */ listMetrics( testRunId: string, + body: MetricRequestPayload, options: ListMetricsOptions = { requestOptions: {} } ): Promise { - return listMetrics(this._client, testRunId, options); + return listMetrics(this._client, testRunId, body, options); } /** Get all test runs with given filters */ diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/api/operations.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/api/operations.ts index e0084b1b6d..6df09ed9c4 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/api/operations.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/api/operations.ts @@ -3,12 +3,12 @@ import { FileInfo, - AppComponent, TestRun, TestRunAppComponents, TestRunServerMetricConfig, MetricDefinitionCollection, MetricNamespaceCollection, + MetricRequestPayload, PagedTimeSeriesElement, PagedTestRun, PagedDimensionValueList, @@ -73,6 +73,7 @@ import { export function _testRunSend( context: Client, testRunId: string, + resource: TestRun, options: TestRunOptions = { requestOptions: {} } ): StreamableMethod< | LoadTestRunCreateOrUpdateTestRun200Response @@ -88,45 +89,51 @@ export function _testRunSend( (options.contentType as any) ?? "application/merge-patch+json", queryParameters: { oldTestRunId: options?.oldTestRunId }, body: { - passFailCriteria: { - passFailMetrics: options?.passFailCriteria?.["passFailMetrics"], - }, - secrets: options?.secrets, - certificate: { - value: options?.certificate?.["value"], - type: options?.certificate?.["type"], - name: options?.certificate?.["name"], - }, - environmentVariables: options?.environmentVariables, - loadTestConfiguration: { - engineInstances: options?.loadTestConfiguration?.["engineInstances"], - splitAllCSVs: options?.loadTestConfiguration?.["splitAllCSVs"], - quickStartTest: options?.loadTestConfiguration?.["quickStartTest"], - optionalLoadTestConfig: !options?.loadTestConfiguration - ?.optionalLoadTestConfig - ? undefined - : { - endpointUrl: - options?.loadTestConfiguration?.optionalLoadTestConfig?.[ - "endpointUrl" - ], - virtualUsers: - options?.loadTestConfiguration?.optionalLoadTestConfig?.[ - "virtualUsers" - ], - rampUpTime: - options?.loadTestConfiguration?.optionalLoadTestConfig?.[ - "rampUpTime" - ], - duration: - options?.loadTestConfiguration?.optionalLoadTestConfig?.[ - "duration" - ], - }, - }, - displayName: options?.displayName, - testId: options?.testId, - description: options?.description, + passFailCriteria: !resource.passFailCriteria + ? undefined + : { passFailMetrics: resource.passFailCriteria?.["passFailMetrics"] }, + secrets: resource["secrets"], + certificate: !resource.certificate + ? undefined + : { + value: resource.certificate?.["value"], + type: resource.certificate?.["type"], + name: resource.certificate?.["name"], + }, + environmentVariables: resource["environmentVariables"], + loadTestConfiguration: !resource.loadTestConfiguration + ? undefined + : { + engineInstances: + resource.loadTestConfiguration?.["engineInstances"], + splitAllCSVs: resource.loadTestConfiguration?.["splitAllCSVs"], + quickStartTest: + resource.loadTestConfiguration?.["quickStartTest"], + optionalLoadTestConfig: !resource.loadTestConfiguration + ?.optionalLoadTestConfig + ? undefined + : { + endpointUrl: + resource.loadTestConfiguration?.optionalLoadTestConfig?.[ + "endpointUrl" + ], + virtualUsers: + resource.loadTestConfiguration?.optionalLoadTestConfig?.[ + "virtualUsers" + ], + rampUpTime: + resource.loadTestConfiguration?.optionalLoadTestConfig?.[ + "rampUpTime" + ], + duration: + resource.loadTestConfiguration?.optionalLoadTestConfig?.[ + "duration" + ], + }, + }, + displayName: resource["displayName"], + testId: resource["testId"], + description: resource["description"], }, }); } @@ -370,16 +377,17 @@ export async function _testRunDeserialize( export async function testRun( context: Client, testRunId: string, + resource: TestRun, options: TestRunOptions = { requestOptions: {} } ): Promise { - const result = await _testRunSend(context, testRunId, options); + const result = await _testRunSend(context, testRunId, resource, options); return _testRunDeserialize(result); } export function _createOrUpdateAppComponentsSend( context: Client, - components: Record, testRunId: string, + body: TestRunAppComponents, options: CreateOrUpdateAppComponentsOptions = { requestOptions: {} } ): StreamableMethod< | LoadTestRunCreateOrUpdateAppComponents200Response @@ -392,7 +400,7 @@ export function _createOrUpdateAppComponentsSend( ...operationOptionsToRequestParameters(options), contentType: (options.contentType as any) ?? "application/merge-patch+json", - body: { components: components }, + body: { components: body["components"] }, }); } @@ -419,14 +427,14 @@ export async function _createOrUpdateAppComponentsDeserialize( /** Associate an app component (collection of azure resources) to a test run */ export async function createOrUpdateAppComponents( context: Client, - components: Record, testRunId: string, + body: TestRunAppComponents, options: CreateOrUpdateAppComponentsOptions = { requestOptions: {} } ): Promise { const result = await _createOrUpdateAppComponentsSend( context, - components, testRunId, + body, options ); return _createOrUpdateAppComponentsDeserialize(result); @@ -435,6 +443,7 @@ export async function createOrUpdateAppComponents( export function _createOrUpdateServerMetricsConfigSend( context: Client, testRunId: string, + body: TestRunServerMetricConfig, options: CreateOrUpdateServerMetricsConfigOptions = { requestOptions: {} } ): StreamableMethod< | LoadTestRunCreateOrUpdateServerMetricsConfig200Response @@ -447,7 +456,7 @@ export function _createOrUpdateServerMetricsConfigSend( ...operationOptionsToRequestParameters(options), contentType: (options.contentType as any) ?? "application/merge-patch+json", - body: { metrics: options?.metrics }, + body: { metrics: body["metrics"] }, }); } @@ -475,11 +484,13 @@ export async function _createOrUpdateServerMetricsConfigDeserialize( export async function createOrUpdateServerMetricsConfig( context: Client, testRunId: string, + body: TestRunServerMetricConfig, options: CreateOrUpdateServerMetricsConfigOptions = { requestOptions: {} } ): Promise { const result = await _createOrUpdateServerMetricsConfigSend( context, testRunId, + body, options ); return _createOrUpdateServerMetricsConfigDeserialize(result); @@ -1067,6 +1078,7 @@ export async function listMetricNamespaces( export function _listMetricsSend( context: Client, testRunId: string, + body: MetricRequestPayload, options: ListMetricsOptions = { requestOptions: {} } ): StreamableMethod< LoadTestRunListMetrics200Response | LoadTestRunListMetricsDefaultResponse @@ -1083,7 +1095,7 @@ export function _listMetricsSend( timespan: options?.timespan, }, body: { - filters: (options?.filters ?? []).map((p) => ({ + filters: (body["filters"] ?? []).map((p) => ({ name: p["name"], values: p["values"], })), @@ -1119,9 +1131,10 @@ export async function _listMetricsDeserialize( export async function listMetrics( context: Client, testRunId: string, + body: MetricRequestPayload, options: ListMetricsOptions = { requestOptions: {} } ): Promise { - const result = await _listMetricsSend(context, testRunId, options); + const result = await _listMetricsSend(context, testRunId, body, options); return _listMetricsDeserialize(result); } diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/index.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/index.ts index c439cfff47..10f2cd0239 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/index.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/index.ts @@ -44,6 +44,7 @@ export { TimeGrain, MetricNamespaceCollection, MetricNamespace, + MetricRequestPayload, DimensionFilter, PagedTimeSeriesElement, TimeSeriesElement, diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/index.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/index.ts index 9edc074687..ee4a125d67 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/index.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/index.ts @@ -40,6 +40,7 @@ export { TimeGrain, MetricNamespaceCollection, MetricNamespace, + MetricRequestPayload, DimensionFilter, PagedTimeSeriesElement, TimeSeriesElement, diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/models.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/models.ts index 36a3a096da..ad07b30388 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/models.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/models.ts @@ -472,6 +472,17 @@ export interface MetricNamespace { name?: string; } +/** Filters to fetch the set of metric */ +export interface MetricRequestPayload { + /** + * Get metrics for specific dimension values. Example: Metric contains dimension + * like SamplerName, Error. To retrieve all the time series data where SamplerName + * is equals to HTTPRequest1 or HTTPRequest2, the DimensionFilter value will be + * {"SamplerName", ["HTTPRequest1", "HTTPRequest2"} + */ + filters?: DimensionFilter[]; +} + /** Dimension name and values to filter */ export interface DimensionFilter { /** The dimension name */ diff --git a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/options.ts b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/options.ts index c47a79ba1a..1c2cdc2012 100644 --- a/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/options.ts +++ b/packages/typespec-test/test/loadtesting_modular/generated/typespec-ts/src/loadTestRun/models/options.ts @@ -2,76 +2,9 @@ // Licensed under the MIT license. import { OperationOptions } from "@azure-rest/core-client"; -import { - PassFailCriteria, - Secret, - CertificateMetadata, - ErrorDetails, - TestRunStatistics, - LoadTestConfiguration, - TestRunArtifacts, - PFTestResult, - Status, - ResourceMetric, - Interval, - DimensionFilter, -} from "./models.js"; +import { Interval } from "./models.js"; export interface TestRunOptions extends OperationOptions { - /** Pass fail criteria for a test. */ - passFailCriteria?: PassFailCriteria; - /** - * Secrets can be stored in an Azure Key Vault or any other secret store. If the - * secret is stored in an Azure Key Vault, the value should be the secret - * identifier and the type should be AKV_SECRET_URI. If the secret is stored - * elsewhere, the secret value should be provided directly and the type should be - * SECRET_VALUE. - */ - secrets?: Record; - /** Certificates metadata */ - certificate?: CertificateMetadata; - /** Environment variables which are defined as a set of pairs. */ - environmentVariables?: Record; - /** Error details if there is any failure in load test run */ - errorDetails?: ErrorDetails[]; - /** Test run statistics. */ - testRunStatistics?: Record; - /** The load test configuration. */ - loadTestConfiguration?: LoadTestConfiguration; - /** Collection of test run artifacts */ - testArtifacts?: TestRunArtifacts; - /** Test result for pass/Fail criteria used during the test run. */ - testResult?: PFTestResult; - /** Number of virtual users, for which test has been run. */ - virtualUsers?: number; - /** Display name of a testRun. */ - displayName?: string; - /** Associated test Id. */ - testId?: string; - /** The test run description. */ - description?: string; - /** The test run status. */ - status?: Status; - /** The test run start DateTime(ISO 8601 literal format). */ - startDateTime?: string; - /** The test run end DateTime(ISO 8601 literal format). */ - endDateTime?: string; - /** Test run initiated time. */ - executedDateTime?: string; - /** Portal url. */ - portalUrl?: string; - /** Test run duration in milliseconds. */ - duration?: number; - /** Subnet ID on which the load test instances should run. */ - subnetId?: string; - /** The creation datetime(ISO 8601 literal format). */ - createdDateTime?: string; - /** The user that created. */ - createdBy?: string; - /** The last Modified datetime(ISO 8601 literal format). */ - lastModifiedDateTime?: string; - /** The user that last modified. */ - lastModifiedBy?: string; /** This request has a JSON Merge Patch body. */ contentType?: string; /** @@ -84,37 +17,11 @@ export interface TestRunOptions extends OperationOptions { } export interface CreateOrUpdateAppComponentsOptions extends OperationOptions { - /** Test run identifier */ - testRunId?: string; - /** The creation datetime(ISO 8601 literal format). */ - createdDateTime?: string; - /** The user that created. */ - createdBy?: string; - /** The last Modified datetime(ISO 8601 literal format). */ - lastModifiedDateTime?: string; - /** The user that last modified. */ - lastModifiedBy?: string; contentType?: string; } export interface CreateOrUpdateServerMetricsConfigOptions extends OperationOptions { - /** Test run identifier */ - testRunId?: string; - /** - * Azure resource metrics collection {metric id : metrics object} (Refer : - * https://docs.microsoft.com/en-us/rest/api/monitor/metric-definitions/list#metricdefinition - * for metric id). - */ - metrics?: Record; - /** The creation datetime(ISO 8601 literal format). */ - createdDateTime?: string; - /** The user that created. */ - createdBy?: string; - /** The last Modified datetime(ISO 8601 literal format). */ - lastModifiedDateTime?: string; - /** The user that last modified. */ - lastModifiedBy?: string; contentType?: string; } @@ -148,13 +55,6 @@ export interface ListMetricDefinitionsOptions extends OperationOptions { export interface ListMetricNamespacesOptions extends OperationOptions {} export interface ListMetricsOptions extends OperationOptions { - /** - * Get metrics for specific dimension values. Example: Metric contains dimension - * like SamplerName, Error. To retrieve all the time series data where SamplerName - * is equals to HTTPRequest1 or HTTPRequest2, the DimensionFilter value will be - * {"SamplerName", ["HTTPRequest1", "HTTPRequest2"} - */ - filters?: DimensionFilter[]; /** The aggregation */ aggregation?: string; /** The interval (i.e. timegrain) of the query. */ diff --git a/packages/typespec-test/test/openai_modular/generated/typespec-ts/review/openai_modular.api.md b/packages/typespec-test/test/openai_modular/generated/typespec-ts/review/openai_modular.api.md index 720d0b4226..6ee40d858e 100644 --- a/packages/typespec-test/test/openai_modular/generated/typespec-ts/review/openai_modular.api.md +++ b/packages/typespec-test/test/openai_modular/generated/typespec-ts/review/openai_modular.api.md @@ -39,10 +39,6 @@ export interface BatchImageGenerationOperationResponse { // @public (undocumented) export interface BeginAzureBatchImageGenerationOptions extends OperationOptions { - n?: number; - responseFormat?: ImageGenerationResponseFormat; - size?: ImageSize; - user?: string; } // @public @@ -63,6 +59,25 @@ export interface ChatCompletions { usage: CompletionsUsage; } +// @public +export interface ChatCompletionsOptions { + dataSources?: AzureChatExtensionConfiguration[]; + frequencyPenalty?: number; + functionCall?: FunctionCallPreset | FunctionName; + functions?: FunctionDefinition[]; + logitBias?: Record; + maxTokens?: number; + messages: ChatMessage[]; + model?: string; + n?: number; + presencePenalty?: number; + stop?: string[]; + stream?: boolean; + temperature?: number; + topP?: number; + user?: string; +} + // @public export interface ChatMessage { content: string | null; @@ -112,6 +127,25 @@ export interface CompletionsLogProbabilityModel { topLogprobs: Record[]; } +// @public +export interface CompletionsOptions { + bestOf?: number; + echo?: boolean; + frequencyPenalty?: number; + logitBias?: Record; + logprobs?: number; + maxTokens?: number; + model?: string; + n?: number; + presencePenalty?: number; + prompt: string[]; + stop?: string[]; + stream?: boolean; + temperature?: number; + topP?: number; + user?: string; +} + // @public export interface CompletionsUsage { completionTokens: number; @@ -148,6 +182,13 @@ export interface Embeddings { usage: EmbeddingsUsage; } +// @public +export interface EmbeddingsOptions { + input: string[]; + model?: string; + user?: string; +} + // @public export interface EmbeddingsUsage { promptTokens: number; @@ -181,61 +222,26 @@ export interface GetAzureBatchImageGenerationOperationStatusOptions extends Oper // @public (undocumented) export interface GetChatCompletionsOptions extends OperationOptions { - dataSources?: AzureChatExtensionConfiguration[]; - frequencyPenalty?: number; - functionCall?: FunctionCallPreset | FunctionName; - functions?: FunctionDefinition[]; - logitBias?: Record; - maxTokens?: number; - model?: string; - n?: number; - presencePenalty?: number; - stop?: string[]; - stream?: boolean; - temperature?: number; - topP?: number; - user?: string; } // @public (undocumented) export interface GetChatCompletionsWithAzureExtensionsOptions extends OperationOptions { - dataSources?: AzureChatExtensionConfiguration[]; - frequencyPenalty?: number; - functionCall?: FunctionCallPreset | FunctionName; - functions?: FunctionDefinition[]; - logitBias?: Record; - maxTokens?: number; - model?: string; - n?: number; - presencePenalty?: number; - stop?: string[]; - stream?: boolean; - temperature?: number; - topP?: number; - user?: string; } // @public (undocumented) export interface GetCompletionsOptions extends OperationOptions { - bestOf?: number; - echo?: boolean; - frequencyPenalty?: number; - logitBias?: Record; - logprobs?: number; - maxTokens?: number; - model?: string; - n?: number; - presencePenalty?: number; - stop?: string[]; - stream?: boolean; - temperature?: number; - topP?: number; - user?: string; } // @public (undocumented) export interface GetEmbeddingsOptions extends OperationOptions { - model?: string; +} + +// @public +export interface ImageGenerationOptions { + n?: number; + prompt: string; + responseFormat?: ImageGenerationResponseFormat; + size?: ImageSize; user?: string; } @@ -264,12 +270,12 @@ export type ImageSize = string; // @public (undocumented) export class OpenAIClient { constructor(endpoint: string, credential: KeyCredential | TokenCredential, options?: OpenAIClientOptions); - beginAzureBatchImageGeneration(prompt: string, options?: BeginAzureBatchImageGenerationOptions): Promise; + beginAzureBatchImageGeneration(body: ImageGenerationOptions, options?: BeginAzureBatchImageGenerationOptions): Promise; getAzureBatchImageGenerationOperationStatus(operationId: string, options?: GetAzureBatchImageGenerationOperationStatusOptions): Promise; - getChatCompletions(messages: ChatMessage[], deploymentId: string, options?: GetChatCompletionsOptions): Promise; - getChatCompletionsWithAzureExtensions(messages: ChatMessage[], deploymentId: string, options?: GetChatCompletionsWithAzureExtensionsOptions): Promise; - getCompletions(prompt: string[], deploymentId: string, options?: GetCompletionsOptions): Promise; - getEmbeddings(input: string[], deploymentId: string, options?: GetEmbeddingsOptions): Promise; + getChatCompletions(deploymentId: string, body: ChatCompletionsOptions, options?: GetChatCompletionsOptions): Promise; + getChatCompletionsWithAzureExtensions(deploymentId: string, body: ChatCompletionsOptions, options?: GetChatCompletionsWithAzureExtensionsOptions): Promise; + getCompletions(deploymentId: string, body: CompletionsOptions, options?: GetCompletionsOptions): Promise; + getEmbeddings(deploymentId: string, body: EmbeddingsOptions, options?: GetEmbeddingsOptions): Promise; } // @public (undocumented) diff --git a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/OpenAIClient.ts b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/OpenAIClient.ts index 5f30dea02e..443e848b87 100644 --- a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/OpenAIClient.ts +++ b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/OpenAIClient.ts @@ -3,11 +3,14 @@ import { TokenCredential, KeyCredential } from "@azure/core-auth"; import { + EmbeddingsOptions, Embeddings, + CompletionsOptions, Completions, - ChatMessage, + ChatCompletionsOptions, ChatCompletions, BatchImageGenerationOperationResponse, + ImageGenerationOptions, } from "./models/models.js"; import { GetEmbeddingsOptions, @@ -45,11 +48,11 @@ export class OpenAIClient { /** Return the embeddings for a given prompt. */ getEmbeddings( - input: string[], deploymentId: string, + body: EmbeddingsOptions, options: GetEmbeddingsOptions = { requestOptions: {} } ): Promise { - return getEmbeddings(this._client, input, deploymentId, options); + return getEmbeddings(this._client, deploymentId, body, options); } /** @@ -58,11 +61,11 @@ export class OpenAIClient { * provided prompt data. */ getCompletions( - prompt: string[], deploymentId: string, + body: CompletionsOptions, options: GetCompletionsOptions = { requestOptions: {} } ): Promise { - return getCompletions(this._client, prompt, deploymentId, options); + return getCompletions(this._client, deploymentId, body, options); } /** @@ -71,11 +74,11 @@ export class OpenAIClient { * provided prompt data. */ getChatCompletions( - messages: ChatMessage[], deploymentId: string, + body: ChatCompletionsOptions, options: GetChatCompletionsOptions = { requestOptions: {} } ): Promise { - return getChatCompletions(this._client, messages, deploymentId, options); + return getChatCompletions(this._client, deploymentId, body, options); } /** @@ -84,16 +87,16 @@ export class OpenAIClient { * other augmentations to the base chat completions capabilities. */ getChatCompletionsWithAzureExtensions( - messages: ChatMessage[], deploymentId: string, + body: ChatCompletionsOptions, options: GetChatCompletionsWithAzureExtensionsOptions = { requestOptions: {}, } ): Promise { return getChatCompletionsWithAzureExtensions( this._client, - messages, deploymentId, + body, options ); } @@ -114,9 +117,9 @@ export class OpenAIClient { /** Starts the generation of a batch of images from a text caption */ beginAzureBatchImageGeneration( - prompt: string, + body: ImageGenerationOptions, options: BeginAzureBatchImageGenerationOptions = { requestOptions: {} } ): Promise { - return beginAzureBatchImageGeneration(this._client, prompt, options); + return beginAzureBatchImageGeneration(this._client, body, options); } } diff --git a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/api/operations.ts b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/api/operations.ts index 81ff5be853..8fc64b3957 100644 --- a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/api/operations.ts +++ b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/api/operations.ts @@ -2,11 +2,14 @@ // Licensed under the MIT license. import { + EmbeddingsOptions, Embeddings, + CompletionsOptions, Completions, - ChatMessage, + ChatCompletionsOptions, ChatCompletions, BatchImageGenerationOperationResponse, + ImageGenerationOptions, } from "../models/models.js"; import { BeginAzureBatchImageGeneration202Response, @@ -40,15 +43,15 @@ import { export function _getEmbeddingsSend( context: Client, - input: string[], deploymentId: string, + body: EmbeddingsOptions, options: GetEmbeddingsOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/deployments/{deploymentId}/embeddings", deploymentId) .post({ ...operationOptionsToRequestParameters(options), - body: { user: options?.user, model: options?.model, input: input }, + body: { user: body["user"], model: body["model"], input: body["input"] }, }); } @@ -74,23 +77,18 @@ export async function _getEmbeddingsDeserialize( /** Return the embeddings for a given prompt. */ export async function getEmbeddings( context: Client, - input: string[], deploymentId: string, + body: EmbeddingsOptions, options: GetEmbeddingsOptions = { requestOptions: {} } ): Promise { - const result = await _getEmbeddingsSend( - context, - input, - deploymentId, - options - ); + const result = await _getEmbeddingsSend(context, deploymentId, body, options); return _getEmbeddingsDeserialize(result); } export function _getCompletionsSend( context: Client, - prompt: string[], deploymentId: string, + body: CompletionsOptions, options: GetCompletionsOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -98,21 +96,21 @@ export function _getCompletionsSend( .post({ ...operationOptionsToRequestParameters(options), body: { - prompt: prompt, - max_tokens: options?.maxTokens, - temperature: options?.temperature, - top_p: options?.topP, - logit_bias: options?.logitBias, - user: options?.user, - n: options?.n, - logprobs: options?.logprobs, - echo: options?.echo, - stop: options?.stop, - presence_penalty: options?.presencePenalty, - frequency_penalty: options?.frequencyPenalty, - best_of: options?.bestOf, - stream: options?.stream, - model: options?.model, + prompt: body["prompt"], + max_tokens: body["maxTokens"], + temperature: body["temperature"], + top_p: body["topP"], + logit_bias: body["logitBias"], + user: body["user"], + n: body["n"], + logprobs: body["logprobs"], + echo: body["echo"], + stop: body["stop"], + presence_penalty: body["presencePenalty"], + frequency_penalty: body["frequencyPenalty"], + best_of: body["bestOf"], + stream: body["stream"], + model: body["model"], }, }); } @@ -215,14 +213,14 @@ export async function _getCompletionsDeserialize( */ export async function getCompletions( context: Client, - prompt: string[], deploymentId: string, + body: CompletionsOptions, options: GetCompletionsOptions = { requestOptions: {} } ): Promise { const result = await _getCompletionsSend( context, - prompt, deploymentId, + body, options ); return _getCompletionsDeserialize(result); @@ -230,8 +228,8 @@ export async function getCompletions( export function _getChatCompletionsSend( context: Client, - messages: ChatMessage[], deploymentId: string, + body: ChatCompletionsOptions, options: GetChatCompletionsOptions = { requestOptions: {} } ): StreamableMethod< GetChatCompletions200Response | GetChatCompletionsDefaultResponse @@ -241,42 +239,25 @@ export function _getChatCompletionsSend( .post({ ...operationOptionsToRequestParameters(options), body: { - messages: (messages ?? []).map((p) => ({ - role: p["role"], - content: p["content"], - name: p["name"], - function_call: !p.functionCall - ? undefined - : { - name: p.functionCall?.["name"], - arguments: p.functionCall?.["arguments"], - }, - context: !p.context - ? undefined - : { - messages: !p.context?.messages - ? undefined - : (p.context?.messages as any), - }, - })), - functions: (options?.functions ?? []).map((p) => ({ + messages: body.messages as any, + functions: (body["functions"] ?? []).map((p) => ({ name: p["name"], description: p["description"], parameters: p["parameters"], })), - function_call: options?.functionCall, - max_tokens: options?.maxTokens, - temperature: options?.temperature, - top_p: options?.topP, - logit_bias: options?.logitBias, - user: options?.user, - n: options?.n, - stop: options?.stop, - presence_penalty: options?.presencePenalty, - frequency_penalty: options?.frequencyPenalty, - stream: options?.stream, - model: options?.model, - dataSources: (options?.dataSources ?? []).map((p) => ({ + function_call: body["functionCall"], + max_tokens: body["maxTokens"], + temperature: body["temperature"], + top_p: body["topP"], + logit_bias: body["logitBias"], + user: body["user"], + n: body["n"], + stop: body["stop"], + presence_penalty: body["presencePenalty"], + frequency_penalty: body["frequencyPenalty"], + stream: body["stream"], + model: body["model"], + dataSources: (body["dataSources"] ?? []).map((p) => ({ type: p["type"], parameters: p["parameters"], })), @@ -393,14 +374,14 @@ export async function _getChatCompletionsDeserialize( */ export async function getChatCompletions( context: Client, - messages: ChatMessage[], deploymentId: string, + body: ChatCompletionsOptions, options: GetChatCompletionsOptions = { requestOptions: {} } ): Promise { const result = await _getChatCompletionsSend( context, - messages, deploymentId, + body, options ); return _getChatCompletionsDeserialize(result); @@ -408,8 +389,8 @@ export async function getChatCompletions( export function _getChatCompletionsWithAzureExtensionsSend( context: Client, - messages: ChatMessage[], deploymentId: string, + body: ChatCompletionsOptions, options: GetChatCompletionsWithAzureExtensionsOptions = { requestOptions: {} } ): StreamableMethod< | GetChatCompletionsWithAzureExtensions200Response @@ -423,42 +404,25 @@ export function _getChatCompletionsWithAzureExtensionsSend( .post({ ...operationOptionsToRequestParameters(options), body: { - messages: (messages ?? []).map((p) => ({ - role: p["role"], - content: p["content"], - name: p["name"], - function_call: !p.functionCall - ? undefined - : { - name: p.functionCall?.["name"], - arguments: p.functionCall?.["arguments"], - }, - context: !p.context - ? undefined - : { - messages: !p.context?.messages - ? undefined - : (p.context?.messages as any), - }, - })), - functions: (options?.functions ?? []).map((p) => ({ + messages: body.messages as any, + functions: (body["functions"] ?? []).map((p) => ({ name: p["name"], description: p["description"], parameters: p["parameters"], })), - function_call: options?.functionCall, - max_tokens: options?.maxTokens, - temperature: options?.temperature, - top_p: options?.topP, - logit_bias: options?.logitBias, - user: options?.user, - n: options?.n, - stop: options?.stop, - presence_penalty: options?.presencePenalty, - frequency_penalty: options?.frequencyPenalty, - stream: options?.stream, - model: options?.model, - dataSources: (options?.dataSources ?? []).map((p) => ({ + function_call: body["functionCall"], + max_tokens: body["maxTokens"], + temperature: body["temperature"], + top_p: body["topP"], + logit_bias: body["logitBias"], + user: body["user"], + n: body["n"], + stop: body["stop"], + presence_penalty: body["presencePenalty"], + frequency_penalty: body["frequencyPenalty"], + stream: body["stream"], + model: body["model"], + dataSources: (body["dataSources"] ?? []).map((p) => ({ type: p["type"], parameters: p["parameters"], })), @@ -577,14 +541,14 @@ export async function _getChatCompletionsWithAzureExtensionsDeserialize( */ export async function getChatCompletionsWithAzureExtensions( context: Client, - messages: ChatMessage[], deploymentId: string, + body: ChatCompletionsOptions, options: GetChatCompletionsWithAzureExtensionsOptions = { requestOptions: {} } ): Promise { const result = await _getChatCompletionsWithAzureExtensionsSend( context, - messages, deploymentId, + body, options ); return _getChatCompletionsWithAzureExtensionsDeserialize(result); @@ -647,7 +611,7 @@ export async function getAzureBatchImageGenerationOperationStatus( export function _beginAzureBatchImageGenerationSend( context: Client, - prompt: string, + body: ImageGenerationOptions, options: BeginAzureBatchImageGenerationOptions = { requestOptions: {} } ): StreamableMethod< | BeginAzureBatchImageGeneration202Response @@ -659,11 +623,11 @@ export function _beginAzureBatchImageGenerationSend( .post({ ...operationOptionsToRequestParameters(options), body: { - prompt: prompt, - n: options?.n, - size: options?.size, - response_format: options?.responseFormat, - user: options?.user, + prompt: body["prompt"], + n: body["n"], + size: body["size"], + response_format: body["responseFormat"], + user: body["user"], }, }); } @@ -696,12 +660,12 @@ export async function _beginAzureBatchImageGenerationDeserialize( /** Starts the generation of a batch of images from a text caption */ export async function beginAzureBatchImageGeneration( context: Client, - prompt: string, + body: ImageGenerationOptions, options: BeginAzureBatchImageGenerationOptions = { requestOptions: {} } ): Promise { const result = await _beginAzureBatchImageGenerationSend( context, - prompt, + body, options ); return _beginAzureBatchImageGenerationDeserialize(result); diff --git a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/index.ts b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/index.ts index 1f84fadf75..e96df752a9 100644 --- a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/index.ts +++ b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/index.ts @@ -3,9 +3,11 @@ export { OpenAIClient, OpenAIClientOptions } from "./OpenAIClient.js"; export { + EmbeddingsOptions, Embeddings, EmbeddingItem, EmbeddingsUsage, + CompletionsOptions, Completions, PromptFilterResult, ContentFilterResults, @@ -15,6 +17,7 @@ export { CompletionsLogProbabilityModel, CompletionsFinishReason, CompletionsUsage, + ChatCompletionsOptions, ChatMessage, ChatRole, FunctionCall, @@ -31,6 +34,7 @@ export { ImageLocation, ImagePayload, AzureOpenAIOperationState, + ImageGenerationOptions, ImageSize, ImageGenerationResponseFormat, GetEmbeddingsOptions, diff --git a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/index.ts b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/index.ts index 3ae2dac66d..644fd24446 100644 --- a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/index.ts +++ b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/index.ts @@ -2,9 +2,11 @@ // Licensed under the MIT license. export { + EmbeddingsOptions, Embeddings, EmbeddingItem, EmbeddingsUsage, + CompletionsOptions, Completions, PromptFilterResult, ContentFilterResults, @@ -14,6 +16,7 @@ export { CompletionsLogProbabilityModel, CompletionsFinishReason, CompletionsUsage, + ChatCompletionsOptions, ChatMessage, ChatRole, FunctionCall, @@ -30,6 +33,7 @@ export { ImageLocation, ImagePayload, AzureOpenAIOperationState, + ImageGenerationOptions, ImageSize, ImageGenerationResponseFormat, } from "./models.js"; diff --git a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/models.ts b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/models.ts index 5968973372..06fe5a17b3 100644 --- a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/models.ts +++ b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/models.ts @@ -3,6 +3,33 @@ import { ErrorModel } from "@azure-rest/core-client"; +/** + * The configuration information for an embeddings request. + * Embeddings measure the relatedness of text strings and are commonly used for search, clustering, + * recommendations, and other similar scenarios. + */ +export interface EmbeddingsOptions { + /** + * An identifier for the caller or end user of the operation. This may be used for tracking + * or rate-limiting purposes. + */ + user?: string; + /** + * The model name to provide as part of this embeddings request. + * Not applicable to Azure OpenAI, where deployment information should be included in the Azure + * resource URI that's connected to. + */ + model?: string; + /** + * Input texts to get embeddings for, encoded as a an array of strings. + * Each input must not exceed 2048 tokens in length. + * + * Unless you are embedding code, we suggest replacing newlines (\n) in your input with a single space, + * as we have observed inferior results when newlines are present. + */ + input: string[]; +} + /** * Representation of the response data from an embeddings request. * Embeddings measure the relatedness of text strings and are commonly used for search, clustering, @@ -34,6 +61,98 @@ export interface EmbeddingsUsage { totalTokens: number; } +/** + * The configuration information for a completions request. + * Completions support a wide variety of tasks and generate text that continues from or "completes" + * provided prompt data. + */ +export interface CompletionsOptions { + /** The prompts to generate completions from. */ + prompt: string[]; + /** The maximum number of tokens to generate. */ + maxTokens?: number; + /** + * The sampling temperature to use that controls the apparent creativity of generated completions. + * Higher values will make output more random while lower values will make results more focused + * and deterministic. + * It is not recommended to modify temperature and top_p for the same completions request as the + * interaction of these two settings is difficult to predict. + */ + temperature?: number; + /** + * An alternative to sampling with temperature called nucleus sampling. This value causes the + * model to consider the results of tokens with the provided probability mass. As an example, a + * value of 0.15 will cause only the tokens comprising the top 15% of probability mass to be + * considered. + * It is not recommended to modify temperature and top_p for the same completions request as the + * interaction of these two settings is difficult to predict. + */ + topP?: number; + /** + * A map between GPT token IDs and bias scores that influences the probability of specific tokens + * appearing in a completions response. Token IDs are computed via external tokenizer tools, while + * bias scores reside in the range of -100 to 100 with minimum and maximum values corresponding to + * a full ban or exclusive selection of a token, respectively. The exact behavior of a given bias + * score varies by model. + */ + logitBias?: Record; + /** + * An identifier for the caller or end user of the operation. This may be used for tracking + * or rate-limiting purposes. + */ + user?: string; + /** + * The number of completions choices that should be generated per provided prompt as part of an + * overall completions response. + * Because this setting can generate many completions, it may quickly consume your token quota. + * Use carefully and ensure reasonable settings for max_tokens and stop. + */ + n?: number; + /** + * A value that controls the emission of log probabilities for the provided number of most likely + * tokens within a completions response. + */ + logprobs?: number; + /** + * A value specifying whether completions responses should include input prompts as prefixes to + * their generated output. + */ + echo?: boolean; + /** A collection of textual sequences that will end completions generation. */ + stop?: string[]; + /** + * A value that influences the probability of generated tokens appearing based on their existing + * presence in generated text. + * Positive values will make tokens less likely to appear when they already exist and increase the + * model's likelihood to output new topics. + */ + presencePenalty?: number; + /** + * A value that influences the probability of generated tokens appearing based on their cumulative + * frequency in generated text. + * Positive values will make tokens less likely to appear as their frequency increases and + * decrease the likelihood of the model repeating the same statements verbatim. + */ + frequencyPenalty?: number; + /** + * A value that controls how many completions will be internally generated prior to response + * formulation. + * When used together with n, best_of controls the number of candidate completions and must be + * greater than n. + * Because this setting can generate many completions, it may quickly consume your token quota. + * Use carefully and ensure reasonable settings for max_tokens and stop. + */ + bestOf?: number; + /** A value indicating whether chat completions should be streamed for this request. */ + stream?: boolean; + /** + * The model name to provide as part of this completions request. + * Not applicable to Azure OpenAI, where deployment information should be included in the Azure + * resource URI that's connected to. + */ + model?: string; +} + /** * Representation of the response data from a completions request. * Completions support a wide variety of tasks and generate text that continues from or "completes" @@ -175,6 +294,98 @@ export interface CompletionsUsage { totalTokens: number; } +/** + * The configuration information for a chat completions request. + * Completions support a wide variety of tasks and generate text that continues from or "completes" + * provided prompt data. + */ +export interface ChatCompletionsOptions { + /** + * The collection of context messages associated with this chat completions request. + * Typical usage begins with a chat message for the System role that provides instructions for + * the behavior of the assistant, followed by alternating messages between the User and + * Assistant roles. + */ + messages: ChatMessage[]; + /** A list of functions the model may generate JSON inputs for. */ + functions?: FunctionDefinition[]; + /** + * Controls how the model responds to function calls. "none" means the model does not call a function, + * and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. + * Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. + * "none" is the default when no functions are present. "auto" is the default if functions are present. + */ + functionCall?: FunctionCallPreset | FunctionName; + /** The maximum number of tokens to generate. */ + maxTokens?: number; + /** + * The sampling temperature to use that controls the apparent creativity of generated completions. + * Higher values will make output more random while lower values will make results more focused + * and deterministic. + * It is not recommended to modify temperature and top_p for the same completions request as the + * interaction of these two settings is difficult to predict. + */ + temperature?: number; + /** + * An alternative to sampling with temperature called nucleus sampling. This value causes the + * model to consider the results of tokens with the provided probability mass. As an example, a + * value of 0.15 will cause only the tokens comprising the top 15% of probability mass to be + * considered. + * It is not recommended to modify temperature and top_p for the same completions request as the + * interaction of these two settings is difficult to predict. + */ + topP?: number; + /** + * A map between GPT token IDs and bias scores that influences the probability of specific tokens + * appearing in a completions response. Token IDs are computed via external tokenizer tools, while + * bias scores reside in the range of -100 to 100 with minimum and maximum values corresponding to + * a full ban or exclusive selection of a token, respectively. The exact behavior of a given bias + * score varies by model. + */ + logitBias?: Record; + /** + * An identifier for the caller or end user of the operation. This may be used for tracking + * or rate-limiting purposes. + */ + user?: string; + /** + * The number of chat completions choices that should be generated for a chat completions + * response. + * Because this setting can generate many completions, it may quickly consume your token quota. + * Use carefully and ensure reasonable settings for max_tokens and stop. + */ + n?: number; + /** A collection of textual sequences that will end completions generation. */ + stop?: string[]; + /** + * A value that influences the probability of generated tokens appearing based on their existing + * presence in generated text. + * Positive values will make tokens less likely to appear when they already exist and increase the + * model's likelihood to output new topics. + */ + presencePenalty?: number; + /** + * A value that influences the probability of generated tokens appearing based on their cumulative + * frequency in generated text. + * Positive values will make tokens less likely to appear as their frequency increases and + * decrease the likelihood of the model repeating the same statements verbatim. + */ + frequencyPenalty?: number; + /** A value indicating whether chat completions should be streamed for this request. */ + stream?: boolean; + /** + * The model name to provide as part of this completions request. + * Not applicable to Azure OpenAI, where deployment information should be included in the Azure + * resource URI that's connected to. + */ + model?: string; + /** + * The configuration entries for Azure OpenAI chat extensions that use them. + * This additional specification is only compatible with Azure OpenAI. + */ + dataSources?: AzureChatExtensionConfiguration[]; +} + /** A single, role-attributed message within a chat completion interaction. */ export interface ChatMessage { /** The role associated with this message payload. */ @@ -375,6 +586,24 @@ export interface ImagePayload { /** The state of a job or item. */ /** "notRunning", "running", "succeeded", "canceled", "failed" */ export type AzureOpenAIOperationState = string; + +/** Represents the request data used to generate images. */ +export interface ImageGenerationOptions { + /** A description of the desired images. */ + prompt: string; + /** The number of images to generate (defaults to 1). */ + n?: number; + /** The desired size of the generated images. Must be one of 256x256, 512x512, or 1024x1024 (defaults to 1024x1024). */ + size?: ImageSize; + /** + * The format in which image generation response items should be presented. + * Azure OpenAI only supports URL response items. + */ + responseFormat?: ImageGenerationResponseFormat; + /** A unique identifier representing your end-user, which can help to monitor and detect abuse. */ + user?: string; +} + /** The desired size of the generated images. Must be one of 256x256, 512x512, or 1024x1024. */ /** "256x256", "512x512", "1024x1024" */ export type ImageSize = string; diff --git a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/options.ts b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/options.ts index 3140d1a945..62d2cc01a8 100644 --- a/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/options.ts +++ b/packages/typespec-test/test/openai_modular/generated/typespec-ts/src/models/options.ts @@ -2,289 +2,18 @@ // Licensed under the MIT license. import { OperationOptions } from "@azure-rest/core-client"; -import { - FunctionDefinition, - FunctionCallPreset, - FunctionName, - AzureChatExtensionConfiguration, - ImageSize, - ImageGenerationResponseFormat, -} from "./models.js"; -export interface GetEmbeddingsOptions extends OperationOptions { - /** - * An identifier for the caller or end user of the operation. This may be used for tracking - * or rate-limiting purposes. - */ - user?: string; - /** - * The model name to provide as part of this embeddings request. - * Not applicable to Azure OpenAI, where deployment information should be included in the Azure - * resource URI that's connected to. - */ - model?: string; -} +export interface GetEmbeddingsOptions extends OperationOptions {} -export interface GetCompletionsOptions extends OperationOptions { - /** The maximum number of tokens to generate. */ - maxTokens?: number; - /** - * The sampling temperature to use that controls the apparent creativity of generated completions. - * Higher values will make output more random while lower values will make results more focused - * and deterministic. - * It is not recommended to modify temperature and top_p for the same completions request as the - * interaction of these two settings is difficult to predict. - */ - temperature?: number; - /** - * An alternative to sampling with temperature called nucleus sampling. This value causes the - * model to consider the results of tokens with the provided probability mass. As an example, a - * value of 0.15 will cause only the tokens comprising the top 15% of probability mass to be - * considered. - * It is not recommended to modify temperature and top_p for the same completions request as the - * interaction of these two settings is difficult to predict. - */ - topP?: number; - /** - * A map between GPT token IDs and bias scores that influences the probability of specific tokens - * appearing in a completions response. Token IDs are computed via external tokenizer tools, while - * bias scores reside in the range of -100 to 100 with minimum and maximum values corresponding to - * a full ban or exclusive selection of a token, respectively. The exact behavior of a given bias - * score varies by model. - */ - logitBias?: Record; - /** - * An identifier for the caller or end user of the operation. This may be used for tracking - * or rate-limiting purposes. - */ - user?: string; - /** - * The number of completions choices that should be generated per provided prompt as part of an - * overall completions response. - * Because this setting can generate many completions, it may quickly consume your token quota. - * Use carefully and ensure reasonable settings for max_tokens and stop. - */ - n?: number; - /** - * A value that controls the emission of log probabilities for the provided number of most likely - * tokens within a completions response. - */ - logprobs?: number; - /** - * A value specifying whether completions responses should include input prompts as prefixes to - * their generated output. - */ - echo?: boolean; - /** A collection of textual sequences that will end completions generation. */ - stop?: string[]; - /** - * A value that influences the probability of generated tokens appearing based on their existing - * presence in generated text. - * Positive values will make tokens less likely to appear when they already exist and increase the - * model's likelihood to output new topics. - */ - presencePenalty?: number; - /** - * A value that influences the probability of generated tokens appearing based on their cumulative - * frequency in generated text. - * Positive values will make tokens less likely to appear as their frequency increases and - * decrease the likelihood of the model repeating the same statements verbatim. - */ - frequencyPenalty?: number; - /** - * A value that controls how many completions will be internally generated prior to response - * formulation. - * When used together with n, best_of controls the number of candidate completions and must be - * greater than n. - * Because this setting can generate many completions, it may quickly consume your token quota. - * Use carefully and ensure reasonable settings for max_tokens and stop. - */ - bestOf?: number; - /** A value indicating whether chat completions should be streamed for this request. */ - stream?: boolean; - /** - * The model name to provide as part of this completions request. - * Not applicable to Azure OpenAI, where deployment information should be included in the Azure - * resource URI that's connected to. - */ - model?: string; -} +export interface GetCompletionsOptions extends OperationOptions {} -export interface GetChatCompletionsOptions extends OperationOptions { - /** A list of functions the model may generate JSON inputs for. */ - functions?: FunctionDefinition[]; - /** - * Controls how the model responds to function calls. "none" means the model does not call a function, - * and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. - * Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. - * "none" is the default when no functions are present. "auto" is the default if functions are present. - */ - functionCall?: FunctionCallPreset | FunctionName; - /** The maximum number of tokens to generate. */ - maxTokens?: number; - /** - * The sampling temperature to use that controls the apparent creativity of generated completions. - * Higher values will make output more random while lower values will make results more focused - * and deterministic. - * It is not recommended to modify temperature and top_p for the same completions request as the - * interaction of these two settings is difficult to predict. - */ - temperature?: number; - /** - * An alternative to sampling with temperature called nucleus sampling. This value causes the - * model to consider the results of tokens with the provided probability mass. As an example, a - * value of 0.15 will cause only the tokens comprising the top 15% of probability mass to be - * considered. - * It is not recommended to modify temperature and top_p for the same completions request as the - * interaction of these two settings is difficult to predict. - */ - topP?: number; - /** - * A map between GPT token IDs and bias scores that influences the probability of specific tokens - * appearing in a completions response. Token IDs are computed via external tokenizer tools, while - * bias scores reside in the range of -100 to 100 with minimum and maximum values corresponding to - * a full ban or exclusive selection of a token, respectively. The exact behavior of a given bias - * score varies by model. - */ - logitBias?: Record; - /** - * An identifier for the caller or end user of the operation. This may be used for tracking - * or rate-limiting purposes. - */ - user?: string; - /** - * The number of chat completions choices that should be generated for a chat completions - * response. - * Because this setting can generate many completions, it may quickly consume your token quota. - * Use carefully and ensure reasonable settings for max_tokens and stop. - */ - n?: number; - /** A collection of textual sequences that will end completions generation. */ - stop?: string[]; - /** - * A value that influences the probability of generated tokens appearing based on their existing - * presence in generated text. - * Positive values will make tokens less likely to appear when they already exist and increase the - * model's likelihood to output new topics. - */ - presencePenalty?: number; - /** - * A value that influences the probability of generated tokens appearing based on their cumulative - * frequency in generated text. - * Positive values will make tokens less likely to appear as their frequency increases and - * decrease the likelihood of the model repeating the same statements verbatim. - */ - frequencyPenalty?: number; - /** A value indicating whether chat completions should be streamed for this request. */ - stream?: boolean; - /** - * The model name to provide as part of this completions request. - * Not applicable to Azure OpenAI, where deployment information should be included in the Azure - * resource URI that's connected to. - */ - model?: string; - /** - * The configuration entries for Azure OpenAI chat extensions that use them. - * This additional specification is only compatible with Azure OpenAI. - */ - dataSources?: AzureChatExtensionConfiguration[]; -} +export interface GetChatCompletionsOptions extends OperationOptions {} export interface GetChatCompletionsWithAzureExtensionsOptions - extends OperationOptions { - /** A list of functions the model may generate JSON inputs for. */ - functions?: FunctionDefinition[]; - /** - * Controls how the model responds to function calls. "none" means the model does not call a function, - * and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. - * Specifying a particular function via `{"name": "my_function"}` forces the model to call that function. - * "none" is the default when no functions are present. "auto" is the default if functions are present. - */ - functionCall?: FunctionCallPreset | FunctionName; - /** The maximum number of tokens to generate. */ - maxTokens?: number; - /** - * The sampling temperature to use that controls the apparent creativity of generated completions. - * Higher values will make output more random while lower values will make results more focused - * and deterministic. - * It is not recommended to modify temperature and top_p for the same completions request as the - * interaction of these two settings is difficult to predict. - */ - temperature?: number; - /** - * An alternative to sampling with temperature called nucleus sampling. This value causes the - * model to consider the results of tokens with the provided probability mass. As an example, a - * value of 0.15 will cause only the tokens comprising the top 15% of probability mass to be - * considered. - * It is not recommended to modify temperature and top_p for the same completions request as the - * interaction of these two settings is difficult to predict. - */ - topP?: number; - /** - * A map between GPT token IDs and bias scores that influences the probability of specific tokens - * appearing in a completions response. Token IDs are computed via external tokenizer tools, while - * bias scores reside in the range of -100 to 100 with minimum and maximum values corresponding to - * a full ban or exclusive selection of a token, respectively. The exact behavior of a given bias - * score varies by model. - */ - logitBias?: Record; - /** - * An identifier for the caller or end user of the operation. This may be used for tracking - * or rate-limiting purposes. - */ - user?: string; - /** - * The number of chat completions choices that should be generated for a chat completions - * response. - * Because this setting can generate many completions, it may quickly consume your token quota. - * Use carefully and ensure reasonable settings for max_tokens and stop. - */ - n?: number; - /** A collection of textual sequences that will end completions generation. */ - stop?: string[]; - /** - * A value that influences the probability of generated tokens appearing based on their existing - * presence in generated text. - * Positive values will make tokens less likely to appear when they already exist and increase the - * model's likelihood to output new topics. - */ - presencePenalty?: number; - /** - * A value that influences the probability of generated tokens appearing based on their cumulative - * frequency in generated text. - * Positive values will make tokens less likely to appear as their frequency increases and - * decrease the likelihood of the model repeating the same statements verbatim. - */ - frequencyPenalty?: number; - /** A value indicating whether chat completions should be streamed for this request. */ - stream?: boolean; - /** - * The model name to provide as part of this completions request. - * Not applicable to Azure OpenAI, where deployment information should be included in the Azure - * resource URI that's connected to. - */ - model?: string; - /** - * The configuration entries for Azure OpenAI chat extensions that use them. - * This additional specification is only compatible with Azure OpenAI. - */ - dataSources?: AzureChatExtensionConfiguration[]; -} + extends OperationOptions {} export interface GetAzureBatchImageGenerationOperationStatusOptions extends OperationOptions {} export interface BeginAzureBatchImageGenerationOptions - extends OperationOptions { - /** The number of images to generate (defaults to 1). */ - n?: number; - /** The desired size of the generated images. Must be one of 256x256, 512x512, or 1024x1024 (defaults to 1024x1024). */ - size?: ImageSize; - /** - * The format in which image generation response items should be presented. - * Azure OpenAI only supports URL response items. - */ - responseFormat?: ImageGenerationResponseFormat; - /** A unique identifier representing your end-user, which can help to monitor and detect abuse. */ - user?: string; -} + extends OperationOptions {} diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/review/widget_dpg.api.md b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/review/widget_dpg.api.md index c63016acc8..08d47a5526 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/review/widget_dpg.api.md +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/review/widget_dpg.api.md @@ -17,6 +17,12 @@ export interface AnalyzeResult { export interface AnalyzeWidgetOptions extends OperationOptions { } +// @public (undocumented) +export interface CreateWidget { + color: "red" | "blue"; + weight: number; +} + // @public (undocumented) export interface CreateWidgetOptions extends OperationOptions { } @@ -34,11 +40,15 @@ export interface ListWidgetsOptions extends OperationOptions { } // @public (undocumented) -export interface UpdateWidgetOptions extends OperationOptions { +export interface UpdateWidget { color?: "red" | "blue"; weight?: number; } +// @public (undocumented) +export interface UpdateWidgetOptions extends OperationOptions { +} + // @public (undocumented) export interface Widget { color: "red" | "blue"; @@ -50,11 +60,11 @@ export interface Widget { export class WidgetServiceClient { constructor(endpoint: string, options?: WidgetServiceClientOptions); analyzeWidget(id: string, options?: AnalyzeWidgetOptions): Promise; - createWidget(weight: number, color: "red" | "blue", options?: CreateWidgetOptions): Promise; + createWidget(body: CreateWidget, options?: CreateWidgetOptions): Promise; deleteWidget(id: string, options?: DeleteWidgetOptions): Promise; getWidget(id: string, options?: GetWidgetOptions): Promise; listWidgets(options?: ListWidgetsOptions): Promise; - updateWidget(id: string, options?: UpdateWidgetOptions): Promise; + updateWidget(id: string, body: UpdateWidget, options?: UpdateWidgetOptions): Promise; } // @public (undocumented) diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/WidgetServiceClient.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/WidgetServiceClient.ts index 42353a42ce..862a4f90b5 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/WidgetServiceClient.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/WidgetServiceClient.ts @@ -1,7 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { Widget, AnalyzeResult } from "./models/models.js"; +import { + Widget, + CreateWidget, + UpdateWidget, + AnalyzeResult, +} from "./models/models.js"; import { ListWidgetsOptions, GetWidgetOptions, @@ -57,11 +62,10 @@ export class WidgetServiceClient { * result in an error. */ createWidget( - weight: number, - color: "red" | "blue", + body: CreateWidget, options: CreateWidgetOptions = { requestOptions: {} } ): Promise { - return createWidget(this._client, weight, color, options); + return createWidget(this._client, body, options); } /** @@ -70,9 +74,10 @@ export class WidgetServiceClient { */ updateWidget( id: string, + body: UpdateWidget, options: UpdateWidgetOptions = { requestOptions: {} } ): Promise { - return updateWidget(this._client, id, options); + return updateWidget(this._client, id, body, options); } /** Delete a widget by ID. */ diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/api/operations.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/api/operations.ts index 34440bb8db..0130df2a8b 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/api/operations.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/api/operations.ts @@ -1,7 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { Widget, AnalyzeResult } from "../models/models.js"; +import { + Widget, + CreateWidget, + UpdateWidget, + AnalyzeResult, +} from "../models/models.js"; import { AnalyzeWidget200Response, AnalyzeWidgetDefaultResponse, @@ -103,15 +108,14 @@ export async function getWidget( export function _createWidgetSend( context: Client, - weight: number, - color: "red" | "blue", + body: CreateWidget, options: CreateWidgetOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/widgets") .post({ ...operationOptionsToRequestParameters(options), - body: { weight: weight, color: color }, + body: { weight: body["weight"], color: body["color"] }, }); } @@ -137,24 +141,24 @@ export async function _createWidgetDeserialize( */ export async function createWidget( context: Client, - weight: number, - color: "red" | "blue", + body: CreateWidget, options: CreateWidgetOptions = { requestOptions: {} } ): Promise { - const result = await _createWidgetSend(context, weight, color, options); + const result = await _createWidgetSend(context, body, options); return _createWidgetDeserialize(result); } export function _updateWidgetSend( context: Client, id: string, + body: UpdateWidget, options: UpdateWidgetOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/widgets/{id}", id) .patch({ ...operationOptionsToRequestParameters(options), - body: { weight: options?.weight, color: options?.color }, + body: { weight: body["weight"], color: body["color"] }, }); } @@ -179,9 +183,10 @@ export async function _updateWidgetDeserialize( export async function updateWidget( context: Client, id: string, + body: UpdateWidget, options: UpdateWidgetOptions = { requestOptions: {} } ): Promise { - const result = await _updateWidgetSend(context, id, options); + const result = await _updateWidgetSend(context, id, body, options); return _updateWidgetDeserialize(result); } diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/index.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/index.ts index 2e594c1f68..6d25e4ab37 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/index.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/index.ts @@ -7,6 +7,8 @@ export { } from "./WidgetServiceClient.js"; export { Widget, + CreateWidget, + UpdateWidget, AnalyzeResult, ListWidgetsOptions, GetWidgetOptions, diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/index.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/index.ts index 3f04419ec5..55d53b8098 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/index.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/index.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -export { Widget, AnalyzeResult } from "./models.js"; +export { Widget, CreateWidget, UpdateWidget, AnalyzeResult } from "./models.js"; export { ListWidgetsOptions, GetWidgetOptions, diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/models.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/models.ts index 5e924b62a6..77cc3a2a8c 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/models.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/models.ts @@ -10,6 +10,20 @@ export interface Widget { color: "red" | "blue"; } +export interface CreateWidget { + /** The weight of the widget. This is an int32, but must be greater than zero. */ + weight: number; + /** The color of the widget. */ + color: "red" | "blue"; +} + +export interface UpdateWidget { + /** The weight of the widget. This is an int32, but must be greater than zero. */ + weight?: number; + /** The color of the widget. */ + color?: "red" | "blue"; +} + export interface AnalyzeResult { summary: string; } diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/options.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/options.ts index 83038b0a3d..d4dbf5bcd0 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/options.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/sources/generated/src/models/options.ts @@ -9,12 +9,7 @@ export interface GetWidgetOptions extends OperationOptions {} export interface CreateWidgetOptions extends OperationOptions {} -export interface UpdateWidgetOptions extends OperationOptions { - /** The weight of the widget. This is an int32, but must be greater than zero. */ - weight?: number; - /** The color of the widget. */ - color?: "red" | "blue"; -} +export interface UpdateWidgetOptions extends OperationOptions {} export interface DeleteWidgetOptions extends OperationOptions {} diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/WidgetServiceClient.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/WidgetServiceClient.ts index 42353a42ce..862a4f90b5 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/WidgetServiceClient.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/WidgetServiceClient.ts @@ -1,7 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { Widget, AnalyzeResult } from "./models/models.js"; +import { + Widget, + CreateWidget, + UpdateWidget, + AnalyzeResult, +} from "./models/models.js"; import { ListWidgetsOptions, GetWidgetOptions, @@ -57,11 +62,10 @@ export class WidgetServiceClient { * result in an error. */ createWidget( - weight: number, - color: "red" | "blue", + body: CreateWidget, options: CreateWidgetOptions = { requestOptions: {} } ): Promise { - return createWidget(this._client, weight, color, options); + return createWidget(this._client, body, options); } /** @@ -70,9 +74,10 @@ export class WidgetServiceClient { */ updateWidget( id: string, + body: UpdateWidget, options: UpdateWidgetOptions = { requestOptions: {} } ): Promise { - return updateWidget(this._client, id, options); + return updateWidget(this._client, id, body, options); } /** Delete a widget by ID. */ diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/api/operations.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/api/operations.ts index 34440bb8db..0130df2a8b 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/api/operations.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/api/operations.ts @@ -1,7 +1,12 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { Widget, AnalyzeResult } from "../models/models.js"; +import { + Widget, + CreateWidget, + UpdateWidget, + AnalyzeResult, +} from "../models/models.js"; import { AnalyzeWidget200Response, AnalyzeWidgetDefaultResponse, @@ -103,15 +108,14 @@ export async function getWidget( export function _createWidgetSend( context: Client, - weight: number, - color: "red" | "blue", + body: CreateWidget, options: CreateWidgetOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/widgets") .post({ ...operationOptionsToRequestParameters(options), - body: { weight: weight, color: color }, + body: { weight: body["weight"], color: body["color"] }, }); } @@ -137,24 +141,24 @@ export async function _createWidgetDeserialize( */ export async function createWidget( context: Client, - weight: number, - color: "red" | "blue", + body: CreateWidget, options: CreateWidgetOptions = { requestOptions: {} } ): Promise { - const result = await _createWidgetSend(context, weight, color, options); + const result = await _createWidgetSend(context, body, options); return _createWidgetDeserialize(result); } export function _updateWidgetSend( context: Client, id: string, + body: UpdateWidget, options: UpdateWidgetOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/widgets/{id}", id) .patch({ ...operationOptionsToRequestParameters(options), - body: { weight: options?.weight, color: options?.color }, + body: { weight: body["weight"], color: body["color"] }, }); } @@ -179,9 +183,10 @@ export async function _updateWidgetDeserialize( export async function updateWidget( context: Client, id: string, + body: UpdateWidget, options: UpdateWidgetOptions = { requestOptions: {} } ): Promise { - const result = await _updateWidgetSend(context, id, options); + const result = await _updateWidgetSend(context, id, body, options); return _updateWidgetDeserialize(result); } diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/index.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/index.ts index 2e594c1f68..6d25e4ab37 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/index.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/index.ts @@ -7,6 +7,8 @@ export { } from "./WidgetServiceClient.js"; export { Widget, + CreateWidget, + UpdateWidget, AnalyzeResult, ListWidgetsOptions, GetWidgetOptions, diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/index.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/index.ts index 3f04419ec5..55d53b8098 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/index.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/index.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -export { Widget, AnalyzeResult } from "./models.js"; +export { Widget, CreateWidget, UpdateWidget, AnalyzeResult } from "./models.js"; export { ListWidgetsOptions, GetWidgetOptions, diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/models.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/models.ts index 5e924b62a6..77cc3a2a8c 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/models.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/models.ts @@ -10,6 +10,20 @@ export interface Widget { color: "red" | "blue"; } +export interface CreateWidget { + /** The weight of the widget. This is an int32, but must be greater than zero. */ + weight: number; + /** The color of the widget. */ + color: "red" | "blue"; +} + +export interface UpdateWidget { + /** The weight of the widget. This is an int32, but must be greater than zero. */ + weight?: number; + /** The color of the widget. */ + color?: "red" | "blue"; +} + export interface AnalyzeResult { summary: string; } diff --git a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/options.ts b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/options.ts index 83038b0a3d..d4dbf5bcd0 100644 --- a/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/options.ts +++ b/packages/typespec-test/test/widget_dpg/generated/typespec-ts/src/models/options.ts @@ -9,12 +9,7 @@ export interface GetWidgetOptions extends OperationOptions {} export interface CreateWidgetOptions extends OperationOptions {} -export interface UpdateWidgetOptions extends OperationOptions { - /** The weight of the widget. This is an int32, but must be greater than zero. */ - weight?: number; - /** The color of the widget. */ - color?: "red" | "blue"; -} +export interface UpdateWidgetOptions extends OperationOptions {} export interface DeleteWidgetOptions extends OperationOptions {} diff --git a/packages/typespec-ts/src/modular/buildCodeModel.ts b/packages/typespec-ts/src/modular/buildCodeModel.ts index e1951192a6..1726637775 100644 --- a/packages/typespec-ts/src/modular/buildCodeModel.ts +++ b/packages/typespec-ts/src/modular/buildCodeModel.ts @@ -52,7 +52,6 @@ import { HttpServer, isStatusCode, HttpOperation, - isHeader, getHttpOperation } from "@typespec/http"; import { getAddedOnVersions } from "@typespec/versioning"; @@ -213,8 +212,16 @@ function handleDiscriminator(context: SdkContext, type: Model) { return undefined; } +function isSchemaProperty(program: Program, property: ModelProperty): boolean { + const headerInfo = getHeaderFieldName(program, property); + const queryInfo = getQueryParamName(program, property); + const pathInfo = getPathParamName(program, property); + const statusCodeinfo = isStatusCode(program, property); + return !(headerInfo || queryInfo || pathInfo || statusCodeinfo); +} + function getEffectiveSchemaType(program: Program, type: Model | Union): Model { - function isSchemaProperty(property: ModelProperty) { + function isSchemaProperty(property: ModelProperty): boolean { const headerInfo = getHeaderFieldName(program, property); const queryInfo = getQueryParamName(program, property); const pathInfo = getPathParamName(program, property); @@ -259,11 +266,7 @@ function processModelProperties( ) { // need to do properties after insertion to avoid infinite recursion for (const property of model.properties.values()) { - if ( - isStatusCode(context.program, property) || - isNeverType(property.type) || - isHeader(context.program, property) - ) { + if (!isSchemaProperty(context.program, property)) { continue; } if (newValue.properties === undefined || newValue.properties === null) { @@ -310,7 +313,9 @@ function getType( } if (enableCache) { - typesMap.set(effectiveModel, newValue); + if (!options.disableEffectiveModel) { + typesMap.set(effectiveModel, newValue); + } if (type.kind === "Union") { for (const t of type.variants.values()) { if (t.type.kind === "Model") { @@ -444,9 +449,6 @@ function emitBodyParameter( const type = getType(context, getBodyType(context.program, httpOperation), { disableEffectiveModel: true }); - if (type.type === "model" && type.name === "") { - type.name = capitalize(httpOperation.operation.name) + "Request"; - } return { contentTypes, @@ -795,7 +797,17 @@ function emitBasicOperation( bodyParameter = undefined; } else { bodyParameter = emitBodyParameter(context, httpOperation); - if ( + if (bodyParameter.type.type === "model" && bodyParameter.type.name === "") { + if (bodyParameter.type.properties.length > 0) { + for (const param of bodyParameter.type.properties) { + // const emittedParam = emitParameter(context, param.type, "Method"); + param.implementation = "Method"; + param.location = param.location ?? "body"; + parameters.push(param); + } + } + bodyParameter = undefined; + } else if ( bodyParameter.type.type === "model" && bodyParameter.type.base === "json" ) { @@ -811,6 +823,21 @@ function emitBasicOperation( } } const name = applyCasing(operation.name, { casing: CASING }); + + /** handle name collision between operation name and parameter signature */ + if (bodyParameter) { + bodyParameter.clientName = + bodyParameter.clientName === name + ? bodyParameter.clientName + "Parameter" + : bodyParameter.clientName; + } + parameters + .filter((param) => { + return param.clientName === name && !param.isReadOnly && param.required; + }) + .forEach((param) => { + param.clientName = param.clientName + "Parameter"; + }); return { name: name, description: getDocStr(context.program, operation), @@ -1225,10 +1252,6 @@ function mapTypeSpecType(context: SdkContext, type: Type): any { } } -function capitalize(name: string): string { - return name[0]!.toUpperCase() + name.slice(1); -} - function emitUnion(context: SdkContext, type: Union): Record { const sdkType = getSdkUnion(context, type); const nonNullOptions = getNonNullOptions(type); diff --git a/packages/typespec-ts/src/modular/buildOperations.ts b/packages/typespec-ts/src/modular/buildOperations.ts index 58b9af7a61..d781c61834 100644 --- a/packages/typespec-ts/src/modular/buildOperations.ts +++ b/packages/typespec-ts/src/modular/buildOperations.ts @@ -159,10 +159,7 @@ export function buildOperationOptions( const optionalParameters = operation.parameters .filter((p) => p.implementation === "Method") .filter((p) => p.optional || p.clientDefaultValue); - const optionalBodyParams = ( - operation.bodyParameter?.type.properties ?? [] - ).filter((p) => p.optional); - const options = [...optionalBodyParams, ...optionalParameters]; + const options = [...optionalParameters]; const name = getOperationOptionsName(operation); diff --git a/packages/typespec-ts/src/modular/emitModels.ts b/packages/typespec-ts/src/modular/emitModels.ts index 2f13125270..7254d33c79 100644 --- a/packages/typespec-ts/src/modular/emitModels.ts +++ b/packages/typespec-ts/src/modular/emitModels.ts @@ -70,7 +70,7 @@ export function buildModels( }); } else { if (!model.name) { - throw new Error("Can't generate a model that has no name"); + continue; } const modelInterface = { name: model.name, @@ -170,4 +170,5 @@ export function buildModelsOptions( id.setModuleSpecifier(id.getModuleSpecifierValue() + ".js"); return id; }); + return modelOptionsFile; } diff --git a/packages/typespec-ts/src/modular/helpers/operationHelpers.ts b/packages/typespec-ts/src/modular/helpers/operationHelpers.ts index 10ad6a382c..4c69865410 100644 --- a/packages/typespec-ts/src/modular/helpers/operationHelpers.ts +++ b/packages/typespec-ts/src/modular/helpers/operationHelpers.ts @@ -186,28 +186,6 @@ function getOperationSignatureParameters( string, OptionalKind > = new Map(); - if (operation.bodyParameter?.type.type === "model") { - (getAllProperties(operation.bodyParameter?.type) ?? []) - .filter((p) => !p.optional) - .filter((p) => !p.readonly) - .map((p) => buildType(p.clientName, p.type, p.format)) - .forEach((p) => parameters.set(p.name, p)); - } else if (operation.bodyParameter?.type.type === "list") { - const bodyArray = operation.bodyParameter; - parameters.set( - bodyArray.clientName, - buildType(bodyArray.clientName, bodyArray.type, bodyArray.type.format) - ); - } else if (operation.bodyParameter?.type.type === "byte-array") { - parameters.set( - operation.bodyParameter.clientName, - buildType( - operation.bodyParameter.clientName, - operation.bodyParameter.type, - operation.bodyParameter.type.format - ) - ); - } operation.parameters .filter( @@ -222,6 +200,16 @@ function getOperationSignatureParameters( parameters.set(p.name, p); }); + if (operation.bodyParameter) { + parameters.set( + operation.bodyParameter?.clientName, + buildType( + operation.bodyParameter.clientName, + operation.bodyParameter.type, + operation.bodyParameter.type.format + ) + ); + } // Add context as the first parameter const contextParam = { name: "context", type: clientType }; @@ -320,7 +308,11 @@ function getRequestParameters( }; for (const param of operationParameters) { - if (param.location === "header" || param.location === "query") { + if ( + param.location === "header" || + param.location === "query" || + param.location === "body" + ) { parametersImplementation[param.location].push( getParameterMap(param, importSet) ); @@ -344,12 +336,19 @@ function getRequestParameters( ",\n" )}},`; } - - paramStr = `${paramStr}${buildBodyParameter( - operation.bodyParameter, - importSet - )}`; - + if ( + operation.bodyParameter === undefined && + parametersImplementation.body.length + ) { + paramStr = `${paramStr}\nbody: {${parametersImplementation.body.join( + ",\n" + )}}`; + } else if (operation.bodyParameter !== undefined) { + paramStr = `${paramStr}${buildBodyParameter( + operation.bodyParameter, + importSet + )}`; + } return paramStr; } @@ -362,24 +361,13 @@ function buildBodyParameter( } if (bodyParameter.type.type === "model") { - const bodyParts: string[] = []; - for (const param of getAllProperties(bodyParameter?.type).filter( - (p) => !p.readonly - ) ?? []) { - if (param.type.type === "model" && isRequired(param)) { - bodyParts.push( - `"${param.restApiName}": {${getRequestModelMapping( - param.type, - param.clientName, - importSet - ).join(",\n")}}` - ); - } else { - bodyParts.push(getParameterMap(param, importSet)); - } - } + const bodyParts: string[] = getRequestModelMapping( + bodyParameter.type, + bodyParameter.clientName, + importSet + ); - if (bodyParameter && getAllProperties(bodyParameter.type).length > 0) { + if (bodyParameter && bodyParts.length > 0) { return `\nbody: {${bodyParts.join(",\n")}},`; } } @@ -499,11 +487,11 @@ function isRequired(param: Parameter | Property): param is RequiredType { function getRequired(param: RequiredType, importSet: Map>) { if (param.type.type === "model") { - return `"${param.restApiName}": ${getRequestModelMapping( + return `"${param.restApiName}": {${getRequestModelMapping( param.type, param.clientName, importSet - ).join(",")}`; + ).join(",")}}`; } return `"${param.restApiName}": ${serializeRequestValue( param.type, diff --git a/packages/typespec-ts/src/modular/helpers/typeHelpers.ts b/packages/typespec-ts/src/modular/helpers/typeHelpers.ts index cf46be0a24..017375b830 100644 --- a/packages/typespec-ts/src/modular/helpers/typeHelpers.ts +++ b/packages/typespec-ts/src/modular/helpers/typeHelpers.ts @@ -80,11 +80,8 @@ export function getType(type: Type, format?: string): TypeMetadata { type.elementType?.type === "model" ? "models.js" : undefined }; case "model": - if (!type.name) { - throw new Error("Unable to process model without name"); - } return { - name: getNullableType(type.name, type), + name: getNullableType(type.name!, type), originModule: "models.js" }; case "string": diff --git a/packages/typespec-ts/src/modular/modularCodeModel.ts b/packages/typespec-ts/src/modular/modularCodeModel.ts index 3ce025dfed..b67e334b14 100644 --- a/packages/typespec-ts/src/modular/modularCodeModel.ts +++ b/packages/typespec-ts/src/modular/modularCodeModel.ts @@ -112,6 +112,7 @@ export type ParameterLocation = | "header" | "query" | "path" + | "body" | "other"; export interface Parameter { diff --git a/packages/typespec-ts/test/commands/cadl-ranch-list.ts b/packages/typespec-ts/test/commands/cadl-ranch-list.ts index 5bc608fb11..31e419a2b4 100644 --- a/packages/typespec-ts/test/commands/cadl-ranch-list.ts +++ b/packages/typespec-ts/test/commands/cadl-ranch-list.ts @@ -235,5 +235,9 @@ export const modularTsps: TypeSpecRanchConfig[] = [ { outputPath: "encode/datetime", inputPath: "encode/datetime" + }, + { + outputPath: "parameters/spread", + inputPath: "parameters/spread" } ]; diff --git a/packages/typespec-ts/test/modularIntegration/encodeBytes.spec.ts b/packages/typespec-ts/test/modularIntegration/encodeBytes.spec.ts index dd1c2679a6..3046770aba 100644 --- a/packages/typespec-ts/test/modularIntegration/encodeBytes.spec.ts +++ b/packages/typespec-ts/test/modularIntegration/encodeBytes.spec.ts @@ -63,10 +63,13 @@ describe("EncodeBytesClient Rest Client", () => { describe("property", () => { it(`should post bytes`, async () => { try { - const result = await client.property.default( + const result = await client.property.default({ + value: stringToUint8Array("dGVzdA==", "base64") + }); + assert.deepEqual( + result.value, stringToUint8Array("dGVzdA==", "base64") ); - assert.deepEqual(result.value, stringToUint8Array("dGVzdA==", "base64")); } catch (err) { assert.fail(err as string); } @@ -74,10 +77,13 @@ describe("EncodeBytesClient Rest Client", () => { it(`should post bytes base64 encoding`, async () => { try { - const result = await client.property.base64( + const result = await client.property.base64({ + value: stringToUint8Array("dGVzdA==", "base64") + }); + assert.deepEqual( + result.value, stringToUint8Array("dGVzdA==", "base64") ); - assert.deepEqual(result.value, stringToUint8Array("dGVzdA==", "base64")); } catch (err) { assert.fail(err as string); } @@ -85,10 +91,13 @@ describe("EncodeBytesClient Rest Client", () => { it(`should post bytes base64url encoding`, async () => { try { - const result = await client.property.base64url( + const result = await client.property.base64url({ + value: stringToUint8Array("dGVzdA", "base64url") + }); + assert.deepEqual( + result.value, stringToUint8Array("dGVzdA", "base64url") ); - assert.deepEqual(result.value, stringToUint8Array("dGVzdA", "base64url")); } catch (err) { assert.fail(err as string); } @@ -96,10 +105,12 @@ describe("EncodeBytesClient Rest Client", () => { it(`should post bytes base64url array`, async () => { try { - const result = await client.property.base64urlArray([ - stringToUint8Array("dGVzdA", "base64url"), - stringToUint8Array("dGVzdA", "base64url") - ]); + const result = await client.property.base64urlArray({ + value: [ + stringToUint8Array("dGVzdA", "base64url"), + stringToUint8Array("dGVzdA", "base64url") + ] + }); assert.deepEqual(result.value, [ stringToUint8Array("dGVzdA", "base64url"), stringToUint8Array("dGVzdA", "base64url") diff --git a/packages/typespec-ts/test/modularIntegration/encodeDatetime.spec.ts b/packages/typespec-ts/test/modularIntegration/encodeDatetime.spec.ts index 6a02e0a085..bc83cc599d 100644 --- a/packages/typespec-ts/test/modularIntegration/encodeDatetime.spec.ts +++ b/packages/typespec-ts/test/modularIntegration/encodeDatetime.spec.ts @@ -71,9 +71,9 @@ describe("EncodeDatetimeClient Rest Client", () => { describe("property", () => { it(`should get default datetime`, async () => { try { - const result = await client.property.default( - new Date("2022-08-26T18:38:00.000Z") - ); + const result = await client.property.default({ + value: new Date("2022-08-26T18:38:00.000Z") + }); assert.deepEqual(result.value, new Date("2022-08-26T18:38:00.000Z")); } catch (err) { assert.fail(err as string); @@ -82,9 +82,9 @@ describe("EncodeDatetimeClient Rest Client", () => { it(`should get rfc3339`, async () => { try { - const result = await client.property.rfc3339( - new Date("2022-08-26T18:38:00.000Z") - ); + const result = await client.property.rfc3339({ + value: new Date("2022-08-26T18:38:00.000Z") + }); assert.deepEqual(result.value, new Date("2022-08-26T18:38:00.000Z")); } catch (err) { assert.fail(err as string); @@ -93,10 +93,13 @@ describe("EncodeDatetimeClient Rest Client", () => { it(`should get rfc7231`, async () => { try { - const result = await client.property.rfc7231( + const result = await client.property.rfc7231({ + value: new Date("Fri, 26 Aug 2022 14:38:00 GMT") + }); + assert.deepEqual( + result.value, new Date("Fri, 26 Aug 2022 14:38:00 GMT") ); - assert.deepEqual(result.value, new Date("Fri, 26 Aug 2022 14:38:00 GMT")); } catch (err) { assert.fail(err as string); } @@ -104,7 +107,9 @@ describe("EncodeDatetimeClient Rest Client", () => { it(`should get unix timestamp`, async () => { try { - const result = await client.property.unixTimestamp(new Date(1686566864)); + const result = await client.property.unixTimestamp({ + value: new Date(1686566864) + }); assert.deepEqual(result.value, new Date(1686566864)); } catch (err) { assert.fail(err as string); @@ -113,11 +118,13 @@ describe("EncodeDatetimeClient Rest Client", () => { it(`should get unix timestamp-array`, async () => { try { - const result = await client.property.unixTimestampArray([ + const result = await client.property.unixTimestampArray({ + value: [new Date(1686566864), new Date(1686734256)] + }); + assert.deepEqual(result.value, [ new Date(1686566864), new Date(1686734256) ]); - assert.deepEqual(result.value, [new Date(1686566864), new Date(1686734256)]); } catch (err) { assert.fail(err as string); } diff --git a/packages/typespec-ts/test/modularIntegration/encodeDuration.spec.ts b/packages/typespec-ts/test/modularIntegration/encodeDuration.spec.ts index fc1e0bed00..5d09be0d33 100644 --- a/packages/typespec-ts/test/modularIntegration/encodeDuration.spec.ts +++ b/packages/typespec-ts/test/modularIntegration/encodeDuration.spec.ts @@ -62,7 +62,7 @@ describe("EncodeDurationClient Rest Client", () => { describe("property", () => { it(`should get default duration`, async () => { try { - const result = await client.property.default("P40D"); + const result = await client.property.default({value: "P40D"}); assert.deepEqual(result.value, "P40D"); } catch (err) { assert.fail(err as string); @@ -71,7 +71,7 @@ describe("EncodeDurationClient Rest Client", () => { it(`should get iso8601 duration`, async () => { try { - const result = await client.property.iso8601("P40D"); + const result = await client.property.iso8601({value: "P40D"}); assert.deepEqual(result.value, "P40D"); } catch (err) { assert.fail(err as string); @@ -80,7 +80,7 @@ describe("EncodeDurationClient Rest Client", () => { it(`should get float seconds`, async () => { try { - const result = await client.property.floatSeconds(35.621); + const result = await client.property.floatSeconds({value: 35.621}); assert.deepEqual(result.value, 35.621); } catch (err) { assert.fail(err as string); @@ -89,7 +89,7 @@ describe("EncodeDurationClient Rest Client", () => { it(`should get int32 seconds`, async () => { try { - const result = await client.property.int32Seconds(36); + const result = await client.property.int32Seconds({value: 36}); assert.deepEqual(result.value, 36); } catch (err) { assert.fail(err as string); @@ -98,9 +98,10 @@ describe("EncodeDurationClient Rest Client", () => { it(`should get int32 seconds array`, async () => { try { - const result = await client.property.floatSecondsArray([ + const result = await client.property.floatSecondsArray({ + value: [ 35.621, 46.781 - ]); + ]}); assert.deepEqual(result.value, [35.621, 46.781]); } catch (err) { assert.fail(err as string); diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/BasicClient.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/BasicClient.ts index b687b2ed80..d58bd31910 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/BasicClient.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/BasicClient.ts @@ -38,20 +38,20 @@ export class BasicClient { /** Creates or updates a User */ createOrUpdate( - name: string, id: number, + resource: User, options: CreateOrUpdateOptions = { requestOptions: {} } ): Promise { - return createOrUpdate(this._client, name, id, options); + return createOrUpdate(this._client, id, resource, options); } /** Creates or replaces a User */ createOrReplace( - name: string, id: number, + resource: User, options: CreateOrReplaceOptions = { requestOptions: {} } ): Promise { - return createOrReplace(this._client, name, id, options); + return createOrReplace(this._client, id, resource, options); } /** Gets a User */ diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/operations.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/operations.ts index 6feb3389e3..621045aec1 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/operations.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/operations.ts @@ -42,8 +42,8 @@ import { export function _createOrUpdateSend( context: Client, - name: string, id: number, + resource: User, options: CreateOrUpdateOptions = { requestOptions: {} } ): StreamableMethod< | CreateOrUpdate200Response @@ -57,8 +57,8 @@ export function _createOrUpdateSend( contentType: (options.contentType as any) ?? "application/merge-patch+json", body: { - name: name, - orders: (options?.orders ?? []).map((p) => ({ + name: resource["name"], + orders: (resource["orders"] ?? []).map((p) => ({ userId: p["userId"], detail: p["detail"], })), @@ -91,18 +91,18 @@ export async function _createOrUpdateDeserialize( /** Creates or updates a User */ export async function createOrUpdate( context: Client, - name: string, id: number, + resource: User, options: CreateOrUpdateOptions = { requestOptions: {} } ): Promise { - const result = await _createOrUpdateSend(context, name, id, options); + const result = await _createOrUpdateSend(context, id, resource, options); return _createOrUpdateDeserialize(result); } export function _createOrReplaceSend( context: Client, - name: string, id: number, + resource: User, options: CreateOrReplaceOptions = { requestOptions: {} } ): StreamableMethod< | CreateOrReplace200Response @@ -114,8 +114,8 @@ export function _createOrReplaceSend( .put({ ...operationOptionsToRequestParameters(options), body: { - name: name, - orders: (options?.orders ?? []).map((p) => ({ + name: resource["name"], + orders: (resource["orders"] ?? []).map((p) => ({ userId: p["userId"], detail: p["detail"], })), @@ -148,11 +148,11 @@ export async function _createOrReplaceDeserialize( /** Creates or replaces a User */ export async function createOrReplace( context: Client, - name: string, id: number, + resource: User, options: CreateOrReplaceOptions = { requestOptions: {} } ): Promise { - const result = await _createOrReplaceSend(context, name, id, options); + const result = await _createOrReplaceSend(context, id, resource, options); return _createOrReplaceDeserialize(result); } diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/options.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/options.ts index dc566023e1..788bd1bc90 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/options.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/options.ts @@ -2,19 +2,13 @@ // Licensed under the MIT license. import { OperationOptions } from "@azure-rest/core-client"; -import { UserOrder } from "./models.js"; export interface CreateOrUpdateOptions extends OperationOptions { - /** The user's order list */ - orders?: UserOrder[]; /** This request has a JSON Merge Patch body. */ contentType?: string; } -export interface CreateOrReplaceOptions extends OperationOptions { - /** The user's order list */ - orders?: UserOrder[]; -} +export interface CreateOrReplaceOptions extends OperationOptions {} export interface GetOptions extends OperationOptions {} diff --git a/packages/typespec-ts/test/modularIntegration/generated/encode/bytes/src/BytesClient.ts b/packages/typespec-ts/test/modularIntegration/generated/encode/bytes/src/BytesClient.ts index dd3ad1c0dd..51174bf15d 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/encode/bytes/src/BytesClient.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/encode/bytes/src/BytesClient.ts @@ -77,28 +77,28 @@ export class BytesClient { }; property = { default: ( - value: Uint8Array, + body: DefaultBytesProperty, options?: PropertyDefaultOptions ): Promise => { - return propertyDefault(this._client, value, options); + return propertyDefault(this._client, body, options); }, base64: ( - value: Uint8Array, + body: Base64BytesProperty, options?: PropertyBase64Options ): Promise => { - return propertyBase64(this._client, value, options); + return propertyBase64(this._client, body, options); }, base64url: ( - value: Uint8Array, + body: Base64urlBytesProperty, options?: PropertyBase64urlOptions ): Promise => { - return propertyBase64url(this._client, value, options); + return propertyBase64url(this._client, body, options); }, base64urlArray: ( - value: Uint8Array[], + body: Base64urlArrayBytesProperty, options?: PropertyBase64urlArrayOptions ): Promise => { - return propertyBase64urlArray(this._client, value, options); + return propertyBase64urlArray(this._client, body, options); }, }; header = { diff --git a/packages/typespec-ts/test/modularIntegration/generated/encode/bytes/src/api/property.ts b/packages/typespec-ts/test/modularIntegration/generated/encode/bytes/src/api/property.ts index 0f345df264..5f6d255713 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/encode/bytes/src/api/property.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/encode/bytes/src/api/property.ts @@ -28,14 +28,14 @@ import { export function _propertyDefaultSend( context: Client, - value: Uint8Array, + body: DefaultBytesProperty, options: PropertyDefaultOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/bytes/property/default") .post({ ...operationOptionsToRequestParameters(options), - body: { value: uint8ArrayToString(value, "base64") }, + body: { value: uint8ArrayToString(body["value"], "base64") }, }); } @@ -56,23 +56,23 @@ export async function _propertyDefaultDeserialize( export async function propertyDefault( context: Client, - value: Uint8Array, + body: DefaultBytesProperty, options: PropertyDefaultOptions = { requestOptions: {} } ): Promise { - const result = await _propertyDefaultSend(context, value, options); + const result = await _propertyDefaultSend(context, body, options); return _propertyDefaultDeserialize(result); } export function _propertyBase64Send( context: Client, - value: Uint8Array, + body: Base64BytesProperty, options: PropertyBase64Options = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/bytes/property/base64") .post({ ...operationOptionsToRequestParameters(options), - body: { value: uint8ArrayToString(value, "base64") }, + body: { value: uint8ArrayToString(body["value"], "base64") }, }); } @@ -93,23 +93,23 @@ export async function _propertyBase64Deserialize( export async function propertyBase64( context: Client, - value: Uint8Array, + body: Base64BytesProperty, options: PropertyBase64Options = { requestOptions: {} } ): Promise { - const result = await _propertyBase64Send(context, value, options); + const result = await _propertyBase64Send(context, body, options); return _propertyBase64Deserialize(result); } export function _propertyBase64urlSend( context: Client, - value: Uint8Array, + body: Base64urlBytesProperty, options: PropertyBase64urlOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/bytes/property/base64url") .post({ ...operationOptionsToRequestParameters(options), - body: { value: uint8ArrayToString(value, "base64url") }, + body: { value: uint8ArrayToString(body["value"], "base64url") }, }); } @@ -130,16 +130,16 @@ export async function _propertyBase64urlDeserialize( export async function propertyBase64url( context: Client, - value: Uint8Array, + body: Base64urlBytesProperty, options: PropertyBase64urlOptions = { requestOptions: {} } ): Promise { - const result = await _propertyBase64urlSend(context, value, options); + const result = await _propertyBase64urlSend(context, body, options); return _propertyBase64urlDeserialize(result); } export function _propertyBase64urlArraySend( context: Client, - value: Uint8Array[], + body: Base64urlArrayBytesProperty, options: PropertyBase64urlArrayOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -147,7 +147,9 @@ export function _propertyBase64urlArraySend( .post({ ...operationOptionsToRequestParameters(options), body: { - value: (value ?? []).map((p) => uint8ArrayToString(p, "base64url")), + value: (body["value"] ?? []).map((p) => + uint8ArrayToString(p, "base64url") + ), }, }); } @@ -168,9 +170,9 @@ export async function _propertyBase64urlArrayDeserialize( export async function propertyBase64urlArray( context: Client, - value: Uint8Array[], + body: Base64urlArrayBytesProperty, options: PropertyBase64urlArrayOptions = { requestOptions: {} } ): Promise { - const result = await _propertyBase64urlArraySend(context, value, options); + const result = await _propertyBase64urlArraySend(context, body, options); return _propertyBase64urlArrayDeserialize(result); } diff --git a/packages/typespec-ts/test/modularIntegration/generated/encode/datetime/src/DatetimeClient.ts b/packages/typespec-ts/test/modularIntegration/generated/encode/datetime/src/DatetimeClient.ts index ff1c463643..d9c4888725 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/encode/datetime/src/DatetimeClient.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/encode/datetime/src/DatetimeClient.ts @@ -81,34 +81,34 @@ export class DatetimeClient { }; property = { default: ( - value: Date, + body: DefaultDatetimeProperty, options?: PropertyDefaultOptions ): Promise => { - return propertyDefault(this._client, value, options); + return propertyDefault(this._client, body, options); }, rfc3339: ( - value: Date, + body: Rfc3339DatetimeProperty, options?: PropertyRfc3339Options ): Promise => { - return propertyRfc3339(this._client, value, options); + return propertyRfc3339(this._client, body, options); }, rfc7231: ( - value: Date, + body: Rfc7231DatetimeProperty, options?: PropertyRfc7231Options ): Promise => { - return propertyRfc7231(this._client, value, options); + return propertyRfc7231(this._client, body, options); }, unixTimestamp: ( - value: Date, + body: UnixTimestampDatetimeProperty, options?: PropertyUnixTimestampOptions ): Promise => { - return propertyUnixTimestamp(this._client, value, options); + return propertyUnixTimestamp(this._client, body, options); }, unixTimestampArray: ( - value: Date[], + body: UnixTimestampArrayDatetimeProperty, options?: PropertyUnixTimestampArrayOptions ): Promise => { - return propertyUnixTimestampArray(this._client, value, options); + return propertyUnixTimestampArray(this._client, body, options); }, }; header = { diff --git a/packages/typespec-ts/test/modularIntegration/generated/encode/datetime/src/api/property.ts b/packages/typespec-ts/test/modularIntegration/generated/encode/datetime/src/api/property.ts index 9f0173a0e4..6b426d277e 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/encode/datetime/src/api/property.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/encode/datetime/src/api/property.ts @@ -30,14 +30,14 @@ import { export function _propertyDefaultSend( context: Client, - value: Date, + body: DefaultDatetimeProperty, options: PropertyDefaultOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/datetime/property/default") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value.toISOString() }, + body: { value: body["value"].toISOString() }, }); } @@ -55,23 +55,23 @@ export async function _propertyDefaultDeserialize( export async function propertyDefault( context: Client, - value: Date, + body: DefaultDatetimeProperty, options: PropertyDefaultOptions = { requestOptions: {} } ): Promise { - const result = await _propertyDefaultSend(context, value, options); + const result = await _propertyDefaultSend(context, body, options); return _propertyDefaultDeserialize(result); } export function _propertyRfc3339Send( context: Client, - value: Date, + body: Rfc3339DatetimeProperty, options: PropertyRfc3339Options = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/datetime/property/rfc3339") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value.toISOString() }, + body: { value: body["value"].toISOString() }, }); } @@ -89,23 +89,23 @@ export async function _propertyRfc3339Deserialize( export async function propertyRfc3339( context: Client, - value: Date, + body: Rfc3339DatetimeProperty, options: PropertyRfc3339Options = { requestOptions: {} } ): Promise { - const result = await _propertyRfc3339Send(context, value, options); + const result = await _propertyRfc3339Send(context, body, options); return _propertyRfc3339Deserialize(result); } export function _propertyRfc7231Send( context: Client, - value: Date, + body: Rfc7231DatetimeProperty, options: PropertyRfc7231Options = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/datetime/property/rfc7231") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value.toUTCString() }, + body: { value: body["value"].toUTCString() }, }); } @@ -123,23 +123,23 @@ export async function _propertyRfc7231Deserialize( export async function propertyRfc7231( context: Client, - value: Date, + body: Rfc7231DatetimeProperty, options: PropertyRfc7231Options = { requestOptions: {} } ): Promise { - const result = await _propertyRfc7231Send(context, value, options); + const result = await _propertyRfc7231Send(context, body, options); return _propertyRfc7231Deserialize(result); } export function _propertyUnixTimestampSend( context: Client, - value: Date, + body: UnixTimestampDatetimeProperty, options: PropertyUnixTimestampOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/datetime/property/unix-timestamp") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value.getTime() }, + body: { value: body["value"].getTime() }, }); } @@ -157,23 +157,23 @@ export async function _propertyUnixTimestampDeserialize( export async function propertyUnixTimestamp( context: Client, - value: Date, + body: UnixTimestampDatetimeProperty, options: PropertyUnixTimestampOptions = { requestOptions: {} } ): Promise { - const result = await _propertyUnixTimestampSend(context, value, options); + const result = await _propertyUnixTimestampSend(context, body, options); return _propertyUnixTimestampDeserialize(result); } export function _propertyUnixTimestampArraySend( context: Client, - value: Date[], + body: UnixTimestampArrayDatetimeProperty, options: PropertyUnixTimestampArrayOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/datetime/property/unix-timestamp-array") .post({ ...operationOptionsToRequestParameters(options), - body: { value: (value ?? []).map((p) => p.getTime()) }, + body: { value: (body["value"] ?? []).map((p) => p.getTime()) }, }); } @@ -191,9 +191,9 @@ export async function _propertyUnixTimestampArrayDeserialize( export async function propertyUnixTimestampArray( context: Client, - value: Date[], + body: UnixTimestampArrayDatetimeProperty, options: PropertyUnixTimestampArrayOptions = { requestOptions: {} } ): Promise { - const result = await _propertyUnixTimestampArraySend(context, value, options); + const result = await _propertyUnixTimestampArraySend(context, body, options); return _propertyUnixTimestampArrayDeserialize(result); } diff --git a/packages/typespec-ts/test/modularIntegration/generated/encode/duration/src/DurationClient.ts b/packages/typespec-ts/test/modularIntegration/generated/encode/duration/src/DurationClient.ts index c5d57d72a9..0584df30b6 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/encode/duration/src/DurationClient.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/encode/duration/src/DurationClient.ts @@ -84,34 +84,34 @@ export class DurationClient { }; property = { default: ( - value: string, + body: DefaultDurationProperty, options?: PropertyDefaultOptions ): Promise => { - return propertyDefault(this._client, value, options); + return propertyDefault(this._client, body, options); }, iso8601: ( - value: string, + body: ISO8601DurationProperty, options?: PropertyIso8601Options ): Promise => { - return propertyIso8601(this._client, value, options); + return propertyIso8601(this._client, body, options); }, int32Seconds: ( - value: number, + body: Int32SecondsDurationProperty, options?: PropertyInt32SecondsOptions ): Promise => { - return propertyInt32Seconds(this._client, value, options); + return propertyInt32Seconds(this._client, body, options); }, floatSeconds: ( - value: number, + body: FloatSecondsDurationProperty, options?: PropertyFloatSecondsOptions ): Promise => { - return propertyFloatSeconds(this._client, value, options); + return propertyFloatSeconds(this._client, body, options); }, floatSecondsArray: ( - value: number[], + body: FloatSecondsDurationArrayProperty, options?: PropertyFloatSecondsArrayOptions ): Promise => { - return propertyFloatSecondsArray(this._client, value, options); + return propertyFloatSecondsArray(this._client, body, options); }, }; header = { diff --git a/packages/typespec-ts/test/modularIntegration/generated/encode/duration/src/api/property.ts b/packages/typespec-ts/test/modularIntegration/generated/encode/duration/src/api/property.ts index 1f1f125607..3c746dc464 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/encode/duration/src/api/property.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/encode/duration/src/api/property.ts @@ -30,14 +30,14 @@ import { export function _propertyDefaultSend( context: Client, - value: string, + body: DefaultDurationProperty, options: PropertyDefaultOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/duration/property/default") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value }, + body: { value: body["value"] }, }); } @@ -55,23 +55,23 @@ export async function _propertyDefaultDeserialize( export async function propertyDefault( context: Client, - value: string, + body: DefaultDurationProperty, options: PropertyDefaultOptions = { requestOptions: {} } ): Promise { - const result = await _propertyDefaultSend(context, value, options); + const result = await _propertyDefaultSend(context, body, options); return _propertyDefaultDeserialize(result); } export function _propertyIso8601Send( context: Client, - value: string, + body: ISO8601DurationProperty, options: PropertyIso8601Options = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/duration/property/iso8601") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value }, + body: { value: body["value"] }, }); } @@ -89,23 +89,23 @@ export async function _propertyIso8601Deserialize( export async function propertyIso8601( context: Client, - value: string, + body: ISO8601DurationProperty, options: PropertyIso8601Options = { requestOptions: {} } ): Promise { - const result = await _propertyIso8601Send(context, value, options); + const result = await _propertyIso8601Send(context, body, options); return _propertyIso8601Deserialize(result); } export function _propertyInt32SecondsSend( context: Client, - value: number, + body: Int32SecondsDurationProperty, options: PropertyInt32SecondsOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/duration/property/int32-seconds") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value }, + body: { value: body["value"] }, }); } @@ -123,23 +123,23 @@ export async function _propertyInt32SecondsDeserialize( export async function propertyInt32Seconds( context: Client, - value: number, + body: Int32SecondsDurationProperty, options: PropertyInt32SecondsOptions = { requestOptions: {} } ): Promise { - const result = await _propertyInt32SecondsSend(context, value, options); + const result = await _propertyInt32SecondsSend(context, body, options); return _propertyInt32SecondsDeserialize(result); } export function _propertyFloatSecondsSend( context: Client, - value: number, + body: FloatSecondsDurationProperty, options: PropertyFloatSecondsOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/duration/property/float-seconds") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value }, + body: { value: body["value"] }, }); } @@ -157,23 +157,23 @@ export async function _propertyFloatSecondsDeserialize( export async function propertyFloatSeconds( context: Client, - value: number, + body: FloatSecondsDurationProperty, options: PropertyFloatSecondsOptions = { requestOptions: {} } ): Promise { - const result = await _propertyFloatSecondsSend(context, value, options); + const result = await _propertyFloatSecondsSend(context, body, options); return _propertyFloatSecondsDeserialize(result); } export function _propertyFloatSecondsArraySend( context: Client, - value: number[], + body: FloatSecondsDurationArrayProperty, options: PropertyFloatSecondsArrayOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/encode/duration/property/float-seconds-array") .post({ ...operationOptionsToRequestParameters(options), - body: { value: value }, + body: { value: body["value"] }, }); } @@ -191,9 +191,9 @@ export async function _propertyFloatSecondsArrayDeserialize( export async function propertyFloatSecondsArray( context: Client, - value: number[], + body: FloatSecondsDurationArrayProperty, options: PropertyFloatSecondsArrayOptions = { requestOptions: {} } ): Promise { - const result = await _propertyFloatSecondsArraySend(context, value, options); + const result = await _propertyFloatSecondsArraySend(context, body, options); return _propertyFloatSecondsArrayDeserialize(result); } diff --git a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/UsageClient.ts b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/UsageClient.ts index fb706cf9fe..8bd16a261a 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/UsageClient.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/UsageClient.ts @@ -1,7 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { OutputRecord, InputOutputRecord } from "./models/models.js"; +import { + InputRecord, + OutputRecord, + InputOutputRecord, +} from "./models/models.js"; import { InputOptions, OutputOptions, @@ -27,10 +31,10 @@ export class UsageClient { } input( - requiredProp: string, + inputParameter: InputRecord, options: InputOptions = { requestOptions: {} } ): Promise { - return input(this._client, requiredProp, options); + return input(this._client, inputParameter, options); } output( @@ -40,9 +44,9 @@ export class UsageClient { } inputAndOutput( - requiredProp: string, + body: InputOutputRecord, options: InputAndOutputOptions = { requestOptions: {} } ): Promise { - return inputAndOutput(this._client, requiredProp, options); + return inputAndOutput(this._client, body, options); } } diff --git a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/api/operations.ts b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/api/operations.ts index edd2a8c41d..eff7c68842 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/api/operations.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/api/operations.ts @@ -1,7 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { OutputRecord, InputOutputRecord } from "../models/models.js"; +import { + InputRecord, + OutputRecord, + InputOutputRecord, +} from "../models/models.js"; import { Input204Response, InputAndOutput200Response, @@ -20,14 +24,14 @@ import { export function _inputSend( context: Client, - requiredProp: string, + inputParameter: InputRecord, options: InputOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/type/model/usage/input") .post({ ...operationOptionsToRequestParameters(options), - body: { requiredProp: requiredProp }, + body: { requiredProp: inputParameter["requiredProp"] }, }); } @@ -43,10 +47,10 @@ export async function _inputDeserialize( export async function input( context: Client, - requiredProp: string, + inputParameter: InputRecord, options: InputOptions = { requestOptions: {} } ): Promise { - const result = await _inputSend(context, requiredProp, options); + const result = await _inputSend(context, inputParameter, options); return _inputDeserialize(result); } @@ -81,14 +85,14 @@ export async function output( export function _inputAndOutputSend( context: Client, - requiredProp: string, + body: InputOutputRecord, options: InputAndOutputOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/type/model/usage/input-output") .post({ ...operationOptionsToRequestParameters(options), - body: { requiredProp: requiredProp }, + body: { requiredProp: body["requiredProp"] }, }); } @@ -106,9 +110,9 @@ export async function _inputAndOutputDeserialize( export async function inputAndOutput( context: Client, - requiredProp: string, + body: InputOutputRecord, options: InputAndOutputOptions = { requestOptions: {} } ): Promise { - const result = await _inputAndOutputSend(context, requiredProp, options); + const result = await _inputAndOutputSend(context, body, options); return _inputAndOutputDeserialize(result); } diff --git a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/index.ts index 87d3a28a02..9212f4ab04 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/index.ts @@ -3,6 +3,7 @@ export { UsageClient, UsageClientOptions } from "./UsageClient.js"; export { + InputRecord, OutputRecord, InputOutputRecord, InputOptions, diff --git a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/models/index.ts index abccc115fc..d33265b180 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/models/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/models/index.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -export { OutputRecord, InputOutputRecord } from "./models.js"; +export { InputRecord, OutputRecord, InputOutputRecord } from "./models.js"; export { InputOptions, OutputOptions, diff --git a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/models/models.ts b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/models/models.ts index d4af06dc90..6ac3ce6414 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/models/models.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/models/usage/generated/src/models/models.ts @@ -1,6 +1,11 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +/** Record used in operation parameters */ +export interface InputRecord { + requiredProp: string; +} + /** Record used in operation return type */ export interface OutputRecord { requiredProp: string; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/SpreadClient.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/SpreadClient.ts new file mode 100644 index 0000000000..8b017b4d10 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/SpreadClient.ts @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { BodyParameter } from "./models/models.js"; +import { + ModelSpreadAsRequestBodyOptions, + AliasSpreadAsRequestBodyOptions, + AliasSpreadAsRequestParameterOptions, + AliasSpreadWithMultipleParametersOptions, +} from "./models/options.js"; +import { + aliasSpreadAsRequestBody, + aliasSpreadAsRequestParameter, + aliasSpreadWithMultipleParameters, + modelSpreadAsRequestBody, + createSpread, + SpreadClientOptions, + SpreadContext, +} from "./api/index.js"; + +export { SpreadClientOptions } from "./api/SpreadContext.js"; + +export class SpreadClient { + private _client: SpreadContext; + + /** Test for the spread operator. */ + constructor(options: SpreadClientOptions = {}) { + this._client = createSpread(options); + } + + model = { + spreadAsRequestBody: ( + body: BodyParameter, + options?: ModelSpreadAsRequestBodyOptions + ): Promise => { + return modelSpreadAsRequestBody(this._client, body, options); + }, + }; + alias = { + spreadAsRequestBody: ( + name: string, + options?: AliasSpreadAsRequestBodyOptions + ): Promise => { + return aliasSpreadAsRequestBody(this._client, name, options); + }, + spreadAsRequestParameter: ( + id: string, + xMsTestHeader: string, + name: string, + options?: AliasSpreadAsRequestParameterOptions + ): Promise => { + return aliasSpreadAsRequestParameter( + this._client, + id, + xMsTestHeader, + name, + options + ); + }, + spreadWithMultipleParameters: ( + id: string, + xMsTestHeader: string, + prop1: string, + prop2: string, + prop3: string, + prop4: string, + prop5: string, + prop6: string, + options?: AliasSpreadWithMultipleParametersOptions + ): Promise => { + return aliasSpreadWithMultipleParameters( + this._client, + id, + xMsTestHeader, + prop1, + prop2, + prop3, + prop4, + prop5, + prop6, + options + ); + }, + }; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/SpreadContext.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/SpreadContext.ts new file mode 100644 index 0000000000..4401085cc1 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/SpreadContext.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { ClientOptions } from "@azure-rest/core-client"; +import { SpreadContext } from "../rest/index.js"; +import getClient from "../rest/index.js"; + +export interface SpreadClientOptions extends ClientOptions {} + +export { SpreadContext } from "../rest/index.js"; + +/** Test for the spread operator. */ +export function createSpread(options: SpreadClientOptions = {}): SpreadContext { + const clientContext = getClient(options); + return clientContext; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/alias.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/alias.ts new file mode 100644 index 0000000000..60b8fb260a --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/alias.ts @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + AliasSpreadAsRequestBody204Response, + AliasSpreadAsRequestParameter204Response, + AliasSpreadWithMultipleParameters204Response, + SpreadContext as Client, +} from "../rest/index.js"; +import { + StreamableMethod, + operationOptionsToRequestParameters, +} from "@azure-rest/core-client"; +import { + AliasSpreadAsRequestBodyOptions, + AliasSpreadAsRequestParameterOptions, + AliasSpreadWithMultipleParametersOptions, +} from "../models/options.js"; + +export function _aliasSpreadAsRequestBodySend( + context: Client, + name: string, + options: AliasSpreadAsRequestBodyOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/spread/alias/request-body") + .put({ + ...operationOptionsToRequestParameters(options), + body: { name: name }, + }); +} + +export async function _aliasSpreadAsRequestBodyDeserialize( + result: AliasSpreadAsRequestBody204Response +): Promise { + if (result.status !== "204") { + throw result.body; + } + + return; +} + +export async function aliasSpreadAsRequestBody( + context: Client, + name: string, + options: AliasSpreadAsRequestBodyOptions = { requestOptions: {} } +): Promise { + const result = await _aliasSpreadAsRequestBodySend(context, name, options); + return _aliasSpreadAsRequestBodyDeserialize(result); +} + +export function _aliasSpreadAsRequestParameterSend( + context: Client, + id: string, + xMsTestHeader: string, + name: string, + options: AliasSpreadAsRequestParameterOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/spread/alias/request-parameter/{id}", id) + .put({ + ...operationOptionsToRequestParameters(options), + headers: { "x-ms-test-header": xMsTestHeader }, + body: { name: name }, + }); +} + +export async function _aliasSpreadAsRequestParameterDeserialize( + result: AliasSpreadAsRequestParameter204Response +): Promise { + if (result.status !== "204") { + throw result.body; + } + + return; +} + +export async function aliasSpreadAsRequestParameter( + context: Client, + id: string, + xMsTestHeader: string, + name: string, + options: AliasSpreadAsRequestParameterOptions = { requestOptions: {} } +): Promise { + const result = await _aliasSpreadAsRequestParameterSend( + context, + id, + xMsTestHeader, + name, + options + ); + return _aliasSpreadAsRequestParameterDeserialize(result); +} + +export function _aliasSpreadWithMultipleParametersSend( + context: Client, + id: string, + xMsTestHeader: string, + prop1: string, + prop2: string, + prop3: string, + prop4: string, + prop5: string, + prop6: string, + options: AliasSpreadWithMultipleParametersOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/spread/alias/multiple-parameters/{id}", id) + .put({ + ...operationOptionsToRequestParameters(options), + headers: { "x-ms-test-header": xMsTestHeader }, + body: { + prop1: prop1, + prop2: prop2, + prop3: prop3, + prop4: prop4, + prop5: prop5, + prop6: prop6, + }, + }); +} + +export async function _aliasSpreadWithMultipleParametersDeserialize( + result: AliasSpreadWithMultipleParameters204Response +): Promise { + if (result.status !== "204") { + throw result.body; + } + + return; +} + +export async function aliasSpreadWithMultipleParameters( + context: Client, + id: string, + xMsTestHeader: string, + prop1: string, + prop2: string, + prop3: string, + prop4: string, + prop5: string, + prop6: string, + options: AliasSpreadWithMultipleParametersOptions = { requestOptions: {} } +): Promise { + const result = await _aliasSpreadWithMultipleParametersSend( + context, + id, + xMsTestHeader, + prop1, + prop2, + prop3, + prop4, + prop5, + prop6, + options + ); + return _aliasSpreadWithMultipleParametersDeserialize(result); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/index.ts new file mode 100644 index 0000000000..b187b64736 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/index.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { + aliasSpreadAsRequestBody, + aliasSpreadAsRequestParameter, + aliasSpreadWithMultipleParameters, +} from "./alias.js"; +export { modelSpreadAsRequestBody } from "./model.js"; +export { + createSpread, + SpreadClientOptions, + SpreadContext, +} from "./SpreadContext.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/model.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/model.ts new file mode 100644 index 0000000000..1a993308ab --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/api/model.ts @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { BodyParameter } from "../models/models.js"; +import { + ModelSpreadAsRequestBody204Response, + SpreadContext as Client, +} from "../rest/index.js"; +import { + StreamableMethod, + operationOptionsToRequestParameters, +} from "@azure-rest/core-client"; +import { ModelSpreadAsRequestBodyOptions } from "../models/options.js"; + +export function _modelSpreadAsRequestBodySend( + context: Client, + body: BodyParameter, + options: ModelSpreadAsRequestBodyOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/spread/model/request-body") + .put({ + ...operationOptionsToRequestParameters(options), + body: { name: body["name"] }, + }); +} + +export async function _modelSpreadAsRequestBodyDeserialize( + result: ModelSpreadAsRequestBody204Response +): Promise { + if (result.status !== "204") { + throw result.body; + } + + return; +} + +export async function modelSpreadAsRequestBody( + context: Client, + body: BodyParameter, + options: ModelSpreadAsRequestBodyOptions = { requestOptions: {} } +): Promise { + const result = await _modelSpreadAsRequestBodySend(context, body, options); + return _modelSpreadAsRequestBodyDeserialize(result); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/index.ts new file mode 100644 index 0000000000..ba4af27542 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/index.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { SpreadClient, SpreadClientOptions } from "./SpreadClient.js"; +export { + BodyParameter, + ModelSpreadAsRequestBodyOptions, + AliasSpreadAsRequestBodyOptions, + AliasSpreadAsRequestParameterOptions, + AliasSpreadWithMultipleParametersOptions, +} from "./models/index.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/logger.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/logger.ts new file mode 100644 index 0000000000..5f2dc4e72e --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/logger.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { createClientLogger } from "@azure/logger"; +export const logger = createClientLogger("parameterSpread"); diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/index.ts new file mode 100644 index 0000000000..806cd89848 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/index.ts @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { BodyParameter } from "./models.js"; +export { + ModelSpreadAsRequestBodyOptions, + AliasSpreadAsRequestBodyOptions, + AliasSpreadAsRequestParameterOptions, + AliasSpreadWithMultipleParametersOptions, +} from "./options.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/models.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/models.ts new file mode 100644 index 0000000000..1414d25091 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/models.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** This is a simple model. */ +export interface BodyParameter { + name: string; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/options.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/options.ts new file mode 100644 index 0000000000..7775443966 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/models/options.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { OperationOptions } from "@azure-rest/core-client"; + +export interface ModelSpreadAsRequestBodyOptions extends OperationOptions {} + +export interface AliasSpreadAsRequestBodyOptions extends OperationOptions {} + +export interface AliasSpreadAsRequestParameterOptions + extends OperationOptions {} + +export interface AliasSpreadWithMultipleParametersOptions + extends OperationOptions {} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/clientDefinitions.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/clientDefinitions.ts new file mode 100644 index 0000000000..a9172e994e --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/clientDefinitions.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + ModelSpreadAsRequestBodyParameters, + AliasSpreadAsRequestBodyParameters, + AliasSpreadAsRequestParameterParameters, + AliasSpreadWithMultipleParametersParameters, +} from "./parameters.js"; +import { + ModelSpreadAsRequestBody204Response, + AliasSpreadAsRequestBody204Response, + AliasSpreadAsRequestParameter204Response, + AliasSpreadWithMultipleParameters204Response, +} from "./responses.js"; +import { Client, StreamableMethod } from "@azure-rest/core-client"; + +export interface ModelSpreadAsRequestBody { + put( + options?: ModelSpreadAsRequestBodyParameters + ): StreamableMethod; +} + +export interface AliasSpreadAsRequestBody { + put( + options?: AliasSpreadAsRequestBodyParameters + ): StreamableMethod; +} + +export interface AliasSpreadAsRequestParameter { + put( + options: AliasSpreadAsRequestParameterParameters + ): StreamableMethod; +} + +export interface AliasSpreadWithMultipleParameters { + put( + options: AliasSpreadWithMultipleParametersParameters + ): StreamableMethod; +} + +export interface Routes { + /** Resource for '/parameters/spread/model/request-body' has methods for the following verbs: put */ + (path: "/parameters/spread/model/request-body"): ModelSpreadAsRequestBody; + /** Resource for '/parameters/spread/alias/request-body' has methods for the following verbs: put */ + (path: "/parameters/spread/alias/request-body"): AliasSpreadAsRequestBody; + /** Resource for '/parameters/spread/alias/request-parameter/\{id\}' has methods for the following verbs: put */ + ( + path: "/parameters/spread/alias/request-parameter/{id}", + id: string + ): AliasSpreadAsRequestParameter; + /** Resource for '/parameters/spread/alias/multiple-parameters/\{id\}' has methods for the following verbs: put */ + ( + path: "/parameters/spread/alias/multiple-parameters/{id}", + id: string + ): AliasSpreadWithMultipleParameters; +} + +export type SpreadContext = Client & { + path: Routes; +}; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/index.ts new file mode 100644 index 0000000000..7123fc2356 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/index.ts @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import SpreadClient from "./spreadClient.js"; + +export * from "./spreadClient.js"; +export * from "./parameters.js"; +export * from "./responses.js"; +export * from "./clientDefinitions.js"; +export * from "./models.js"; + +export default SpreadClient; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/models.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/models.ts new file mode 100644 index 0000000000..1414d25091 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/models.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** This is a simple model. */ +export interface BodyParameter { + name: string; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/parameters.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/parameters.ts new file mode 100644 index 0000000000..06cf04d9be --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/parameters.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { RawHttpHeadersInput } from "@azure/core-rest-pipeline"; +import { RequestParameters } from "@azure-rest/core-client"; +import { BodyParameter } from "./models.js"; + +export interface ModelSpreadAsRequestBodyBodyParam { + body?: BodyParameter; +} + +export type ModelSpreadAsRequestBodyParameters = + ModelSpreadAsRequestBodyBodyParam & RequestParameters; + +export interface AliasSpreadAsRequestBodyBodyParam { + body?: { name: string }; +} + +export type AliasSpreadAsRequestBodyParameters = + AliasSpreadAsRequestBodyBodyParam & RequestParameters; + +export interface AliasSpreadAsRequestParameterHeaders { + "x-ms-test-header": string; +} + +export interface AliasSpreadAsRequestParameterBodyParam { + body?: { name: string }; +} + +export interface AliasSpreadAsRequestParameterHeaderParam { + headers: RawHttpHeadersInput & AliasSpreadAsRequestParameterHeaders; +} + +export type AliasSpreadAsRequestParameterParameters = + AliasSpreadAsRequestParameterHeaderParam & + AliasSpreadAsRequestParameterBodyParam & + RequestParameters; + +export interface AliasSpreadWithMultipleParametersHeaders { + "x-ms-test-header": string; +} + +export interface AliasSpreadWithMultipleParametersBodyParam { + body?: { + prop1: string; + prop2: string; + prop3: string; + prop4: string; + prop5: string; + prop6: string; + }; +} + +export interface AliasSpreadWithMultipleParametersHeaderParam { + headers: RawHttpHeadersInput & AliasSpreadWithMultipleParametersHeaders; +} + +export type AliasSpreadWithMultipleParametersParameters = + AliasSpreadWithMultipleParametersHeaderParam & + AliasSpreadWithMultipleParametersBodyParam & + RequestParameters; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/responses.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/responses.ts new file mode 100644 index 0000000000..c826e65566 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/responses.ts @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { HttpResponse } from "@azure-rest/core-client"; + +/** There is no content to send for this request, but the headers may be useful. */ +export interface ModelSpreadAsRequestBody204Response extends HttpResponse { + status: "204"; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface AliasSpreadAsRequestBody204Response extends HttpResponse { + status: "204"; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface AliasSpreadAsRequestParameter204Response extends HttpResponse { + status: "204"; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface AliasSpreadWithMultipleParameters204Response + extends HttpResponse { + status: "204"; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/spreadClient.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/spreadClient.ts new file mode 100644 index 0000000000..d5567b1f72 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/src/rest/spreadClient.ts @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { getClient, ClientOptions } from "@azure-rest/core-client"; +import { logger } from "../logger.js"; +import { SpreadContext } from "./clientDefinitions.js"; + +/** + * Initialize a new instance of `SpreadContext` + * @param options - the parameter for all optional parameters + */ +export default function createClient( + options: ClientOptions = {} +): SpreadContext { + const baseUrl = options.baseUrl ?? `http://localhost:3000`; + options.apiVersion = options.apiVersion ?? "1.0.0"; + const userAgentInfo = `azsdk-js-parameterSpread-rest/1.0.0-beta.1`; + const userAgentPrefix = + options.userAgentOptions && options.userAgentOptions.userAgentPrefix + ? `${options.userAgentOptions.userAgentPrefix} ${userAgentInfo}` + : `${userAgentInfo}`; + options = { + ...options, + userAgentOptions: { + userAgentPrefix, + }, + loggingOptions: { + logger: options.loggingOptions?.logger ?? logger.info, + }, + }; + + const client = getClient(baseUrl, options) as SpreadContext; + + return client; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/tspconfig.yaml b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/tspconfig.yaml new file mode 100644 index 0000000000..8befb673ed --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/spread/tspconfig.yaml @@ -0,0 +1,14 @@ +emit: + - "@azure-tools/typespec-ts" +options: + "@azure-tools/typespec-ts": + "emitter-output-dir": "{project-root}" + generateMetadata: false + generateTest: false + addCredentials: false + azureSdkForJs: false + enableOperationGroup: true + isTypeSpecTest: true + isModularLibrary: true + packageDetails: + name: "@msinternal/parameterSpread" diff --git a/packages/typespec-ts/test/modularIntegration/spreadParameters.spec.ts b/packages/typespec-ts/test/modularIntegration/spreadParameters.spec.ts new file mode 100644 index 0000000000..876498dd8c --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/spreadParameters.spec.ts @@ -0,0 +1,58 @@ +import { SpreadClient } from "./generated/parameters/spread/src/index.js"; +import { assert } from "chai"; +describe("SpreadClient Client", () => { + let client: SpreadClient; + + beforeEach(() => { + client = new SpreadClient({ allowInsecureConnection: true }); + }); + + it("should spread named model", async () => { + try { + const result = await client.model.spreadAsRequestBody({ name: "foo" }); + assert.isUndefined(result); + } catch (err) { + assert.fail(err as string); + } + }); + + it("should spread alias with only body param", async () => { + try { + const result = await client.alias.spreadAsRequestBody("foo"); + assert.isUndefined(result); + } catch (err) { + assert.fail(err as string); + } + }); + + it("should spread alias with mixed params", async () => { + try { + const result = await client.alias.spreadAsRequestParameter( + "1", + "bar", + "foo" + ); + assert.isUndefined(result); + } catch (err) { + assert.fail(err as string); + } + }); + + it("should spread alias with more than 5 params", async () => { + try { + const result = await client.alias.spreadWithMultipleParameters( + "1", + "bar", + "foo1", + "foo2", + "foo3", + "foo4", + "foo5", + "foo6" + ); + assert.isUndefined(result); + } catch (err) { + assert.fail(err as string); + } + }); +}); diff --git a/packages/typespec-ts/test/modularIntegration/usage.spec.ts b/packages/typespec-ts/test/modularIntegration/usage.spec.ts index 221695f3cb..0d17f2d9f5 100644 --- a/packages/typespec-ts/test/modularIntegration/usage.spec.ts +++ b/packages/typespec-ts/test/modularIntegration/usage.spec.ts @@ -19,14 +19,14 @@ describe("UsageContext Classical Client", () => { it("should input", async () => { try { - const result = await client.input(EXPECTED_VALUE); + const result = await client.input({requiredProp: EXPECTED_VALUE}); assert.isUndefined(result); } catch (err) { assert.fail(err as string); } }); - it("should ouput", async () => { + it("should output", async () => { try { const result = await client.output(); assert.isNotNull(result); @@ -38,7 +38,7 @@ describe("UsageContext Classical Client", () => { it("should inputAndOutput", async () => { try { - const result = await client.inputAndOutput(EXPECTED_VALUE); + const result = await client.inputAndOutput({requiredProp: EXPECTED_VALUE}); assert.isNotNull(result); assert.strictEqual(result.requiredProp, EXPECTED_VALUE); } catch (err) { @@ -58,7 +58,7 @@ describe("UsageContext API Operations", () => { it("should input", async () => { try { - const result = await input(context, EXPECTED_VALUE); + const result = await input(context, {requiredProp: EXPECTED_VALUE}); assert.isUndefined(result); } catch (err) { assert.fail(err as string); @@ -67,7 +67,7 @@ describe("UsageContext API Operations", () => { it("should inputAndOutput", async () => { try { - const result = await inputAndOutput(context, EXPECTED_VALUE); + const result = await inputAndOutput(context, { requiredProp: EXPECTED_VALUE}); assert.isNotNull(result); assert.strictEqual(result.requiredProp, EXPECTED_VALUE); } catch (err) { diff --git a/packages/typespec-ts/test/modularUnit/modelsGenerator.spec.ts b/packages/typespec-ts/test/modularUnit/modelsGenerator.spec.ts index c0d9efd5e1..2a1040bbb7 100644 --- a/packages/typespec-ts/test/modularUnit/modelsGenerator.spec.ts +++ b/packages/typespec-ts/test/modularUnit/modelsGenerator.spec.ts @@ -53,10 +53,7 @@ describe("modular encode test for property type datetime", () => { export function _readSend( context: Client, - prop1: Date, - prop2: Date, - prop3: Date, - prop4: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -64,10 +61,10 @@ describe("modular encode test for property type datetime", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: prop1.toDateString(), - prop2: prop2.toTimeString(), - prop3: prop3.toISOString(), - prop4: prop4, + prop1: body["prop1"].toDateString(), + prop2: body["prop2"].toTimeString(), + prop3: body["prop3"].toISOString(), + prop4: body["prop4"], }, }); } @@ -87,13 +84,10 @@ describe("modular encode test for property type datetime", () => { export async function read( context: Client, - prop1: Date, - prop2: Date, - prop3: Date, - prop4: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, prop2, prop3, prop4, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -185,8 +179,7 @@ describe("modular encode test for property type datetime", () => { export function _readSend( context: Client, - prop1: Date, - prop2: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -194,8 +187,8 @@ describe("modular encode test for property type datetime", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: prop1.toISOString(), - prop2: prop2, + prop1: body["prop1"].toISOString(), + prop2: body["prop2"], }, }); } @@ -213,11 +206,10 @@ describe("modular encode test for property type datetime", () => { export async function read( context: Client, - prop1: Date, - prop2: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, prop2, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -258,8 +250,7 @@ describe("modular encode test for property type datetime", () => { export function _readSend( context: Client, - prop1: Date, - prop2: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -267,8 +258,8 @@ describe("modular encode test for property type datetime", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: prop1.toUTCString(), - prop2: prop2, + prop1: body["prop1"].toUTCString(), + prop2: body["prop2"], }, }); } @@ -286,11 +277,10 @@ describe("modular encode test for property type datetime", () => { export async function read( context: Client, - prop1: Date, - prop2: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, prop2, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -328,7 +318,7 @@ describe("modular encode test for property type datetime", () => { export function _readSend( context: Client, - prop1: Date, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -336,7 +326,7 @@ describe("modular encode test for property type datetime", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: prop1.getTime(), + prop1: body["prop1"].getTime() }, }); } @@ -353,10 +343,10 @@ describe("modular encode test for property type datetime", () => { export async function read( context: Client, - prop1: Date, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -395,7 +385,7 @@ describe("modular encode test for property type duration", () => { export function _readSend( context: Client, - prop1: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -403,7 +393,7 @@ describe("modular encode test for property type duration", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: prop1, + prop1: body["prop1"], }, }); } @@ -420,10 +410,10 @@ describe("modular encode test for property type duration", () => { export async function read( context: Client, - prop1: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -461,7 +451,7 @@ describe("modular encode test for property type duration", () => { export function _readSend( context: Client, - prop1: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -469,7 +459,7 @@ describe("modular encode test for property type duration", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: prop1, + prop1: body["prop1"], }, }); } @@ -486,10 +476,10 @@ describe("modular encode test for property type duration", () => { export async function read( context: Client, - prop1: string, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -530,8 +520,7 @@ describe("modular encode test for property type duration", () => { export function _readSend( context: Client, - prop1: number, - prop2: number, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -539,8 +528,8 @@ describe("modular encode test for property type duration", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: prop1, - prop2: prop2, + prop1: body["prop1"], + prop2: body["prop2"], }, }); } @@ -558,11 +547,10 @@ describe("modular encode test for property type duration", () => { export async function read( context: Client, - prop1: number, - prop2: number, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, prop2, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -602,7 +590,7 @@ describe("modular encode test for property type bytes", () => { export function _readSend( context: Client, - prop1: Uint8Array, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -610,7 +598,7 @@ describe("modular encode test for property type bytes", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: uint8ArrayToString(prop1, "base64"), + prop1: uint8ArrayToString(body["prop1"], "base64"), }, }); } @@ -630,10 +618,10 @@ describe("modular encode test for property type bytes", () => { export async function read( context: Client, - prop1: Uint8Array, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -672,7 +660,7 @@ describe("modular encode test for property type bytes", () => { export function _readSend( context: Client, - prop1: Uint8Array, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -680,7 +668,7 @@ describe("modular encode test for property type bytes", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: uint8ArrayToString(prop1, "base64"), + prop1: uint8ArrayToString(body["prop1"], "base64"), }, }); } @@ -700,10 +688,10 @@ describe("modular encode test for property type bytes", () => { export async function read( context: Client, - prop1: Uint8Array, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -742,7 +730,7 @@ describe("modular encode test for property type bytes", () => { export function _readSend( context: Client, - prop1: Uint8Array, + body: Foo, options: ReadOptions = { requestOptions: {} } ): StreamableMethod { return context @@ -750,7 +738,7 @@ describe("modular encode test for property type bytes", () => { .post({ ...operationOptionsToRequestParameters(options), body: { - prop1: uint8ArrayToString(prop1, "base64url"), + prop1: uint8ArrayToString(body["prop1"], "base64url"), }, }); } @@ -770,10 +758,10 @@ describe("modular encode test for property type bytes", () => { export async function read( context: Client, - prop1: Uint8Array, + body: Foo, options: ReadOptions = { requestOptions: {} } ): Promise { - const result = await _readSend(context, prop1, options); + const result = await _readSend(context, body, options); return _readDeserialize(result); }`, true @@ -1230,3 +1218,399 @@ describe("inheritance & polymorphism", () => { ); }); }); + +describe("flatten alias if spread", () => { + it("should flatten alias if spread in the payload with required parameters", async () => { + const tspContent = ` + alias Foo = { + prop1: string; + prop2: int64; + prop3: utcDateTime; + prop4: offsetDateTime; + prop5: Bar; + }; + model Bar { + prop1: string; + prop2: int64; + } + op read(@path pathParam: string, @query queryParam: string, ...Foo): OkResponse; + `; + const modelFile = await emitModularModelsFromTypeSpec(tspContent); + assert.ok(modelFile); + assertEqualContent( + modelFile?.getFullText()!, + ` + export interface Bar { + prop1: string; + prop2: number; + }` + ); + const operationFiles = await emitModularOperationsFromTypeSpec(tspContent); + assert.ok(operationFiles); + assert.equal(operationFiles?.length, 1); + assertEqualContent( + operationFiles?.[0]?.getFullText()!, + ` + import { TestingContext as Client } from "../rest/index.js"; + import { + StreamableMethod, + operationOptionsToRequestParameters, + } from "@azure-rest/core-client"; + export function _readSend( + context: Client, + pathParam: string, + queryParam: string, + prop1: string, + prop2: number, + prop3: Date, + prop4: string, + prop5: Bar, + options: ReadOptions = { requestOptions: {} } + ): StreamableMethod { + return context + .path("/{pathParam}", pathParam) + .post({ + ...operationOptionsToRequestParameters(options), + queryParameters: { queryParam: queryParam }, + body: { + prop1: prop1, + prop2: prop2, + prop3: prop3.toISOString(), + prop4: prop4, + prop5: { prop1: prop5["prop1"], prop2: prop5["prop2"] }, + }, + }); + } + export async function _readDeserialize(result: Read200Response): Promise { + if (result.status !== "200") { + throw result.body; + } + return; + } + export async function read( + context: Client, + pathParam: string, + queryParam: string, + prop1: string, + prop2: number, + prop3: Date, + prop4: string, + prop5: Bar, + options: ReadOptions = { requestOptions: {} } + ): Promise { + const result = await _readSend( + context, + pathParam, + queryParam, + prop1, + prop2, + prop3, + prop4, + prop5, + options + ); + return _readDeserialize(result); + }`, + true + ); + }); + + it("should flatten alias if spread in the payload with optional parameters", async () => { + const tspContent = ` + alias Foo = { + prop1: string; + prop2: int64; + prop3?: utcDateTime; + prop4: offsetDateTime; + prop5?: Bar; + }; + model Bar { + prop1: string; + prop2: int64; + } + op read(@path pathParam: string, @query queryParam: string, ...Foo): OkResponse; + `; + const modelFile = await emitModularModelsFromTypeSpec(tspContent); + assert.ok(modelFile); + assertEqualContent( + modelFile?.getFullText()!, + ` + export interface Bar { + prop1: string; + prop2: number; + }` + ); + const optionFile = await emitModularModelsFromTypeSpec(tspContent, true); + assert.ok(optionFile); + assertEqualContent( + optionFile?.getFullText()!, + ` + import { OperationOptions } from "@azure-rest/core-client"; + + export interface ReadOptions extends OperationOptions { + prop3?: Date; + prop5?: Bar; + }` + ); + const operationFiles = await emitModularOperationsFromTypeSpec(tspContent); + assert.ok(operationFiles); + assert.equal(operationFiles?.length, 1); + assertEqualContent( + operationFiles?.[0]?.getFullText()!, + ` + import { TestingContext as Client } from "../rest/index.js"; + import { + StreamableMethod, + operationOptionsToRequestParameters, + } from "@azure-rest/core-client"; + export function _readSend( + context: Client, + pathParam: string, + queryParam: string, + prop1: string, + prop2: number, + prop4: string, + options: ReadOptions = { requestOptions: {} } + ): StreamableMethod { + return context + .path("/{pathParam}", pathParam) + .post({ + ...operationOptionsToRequestParameters(options), + queryParameters: { queryParam: queryParam }, + body: { + prop1: prop1, + prop2: prop2, + prop3: options?.prop3?.toISOString(), + prop4: prop4, + prop5: { + prop1: options?.prop5?.["prop1"], + prop2: options?.prop5?.["prop2"], + }, + }, + }); + } + export async function _readDeserialize(result: Read200Response): Promise { + if (result.status !== "200") { + throw result.body; + } + return; + } + export async function read( + context: Client, + pathParam: string, + queryParam: string, + prop1: string, + prop2: number, + prop4: string, + options: ReadOptions = { requestOptions: {} } + ): Promise { + const result = await _readSend( + context, + pathParam, + queryParam, + prop1, + prop2, + prop4, + options + ); + return _readDeserialize(result); + }`, + true + ); + }); + + it("should flatten alias if spread in the payload with optional parameters", async () => { + const tspContent = ` + alias Foo = { + @path + prop1: string; + prop2: int64; + prop3?: utcDateTime; + @query + prop4: offsetDateTime; + prop5?: Bar; + }; + model Bar { + prop1: string; + prop2: int64; + } + op read(@path pathParam: string, ...Foo, @query queryParam: string): OkResponse; + `; + const modelFile = await emitModularModelsFromTypeSpec(tspContent); + assert.ok(modelFile); + assertEqualContent( + modelFile?.getFullText()!, + ` + export interface Bar { + prop1: string; + prop2: number; + }` + ); + const optionFile = await emitModularModelsFromTypeSpec(tspContent, true); + assert.ok(optionFile); + assertEqualContent( + optionFile?.getFullText()!, + ` + import { OperationOptions } from "@azure-rest/core-client"; + + export interface ReadOptions extends OperationOptions { + prop3?: Date; + prop5?: Bar; + }` + ); + const operationFiles = await emitModularOperationsFromTypeSpec(tspContent); + assert.ok(operationFiles); + assert.equal(operationFiles?.length, 1); + assertEqualContent( + operationFiles?.[0]?.getFullText()!, + ` + import { TestingContext as Client } from "../rest/index.js"; + import { + StreamableMethod, + operationOptionsToRequestParameters, + } from "@azure-rest/core-client"; + export function _readSend( + context: Client, + pathParam: string, + prop1: string, + prop4: string, + queryParam: string, + prop2: number, + options: ReadOptions = { requestOptions: {} } + ): StreamableMethod { + return context + .path("/{pathParam}/{prop1}", pathParam, prop1) + .post({ + ...operationOptionsToRequestParameters(options), + queryParameters: { prop4: prop4, queryParam: queryParam }, + body: { + prop2: prop2, + prop3: options?.prop3?.toISOString(), + prop5: { + prop1: options?.prop5?.["prop1"], + prop2: options?.prop5?.["prop2"], + }, + }, + }); + } + export async function _readDeserialize(result: Read200Response): Promise { + if (result.status !== "200") { + throw result.body; + } + return; + } + export async function read( + context: Client, + pathParam: string, + prop1: string, + prop4: string, + queryParam: string, + prop2: number, + options: ReadOptions = { requestOptions: {} } + ): Promise { + const result = await _readSend( + context, + pathParam, + prop1, + prop4, + queryParam, + prop2, + options + ); + return _readDeserialize(result); + }`, + true + ); + }); + + it("should not flatten model if spread in the payload with required parameters", async () => { + const tspContent = ` + model Foo { + prop1: string; + prop2: int64; + prop3: utcDateTime; + prop4: offsetDateTime; + prop5: Bar; + } + model Bar { + prop1: string; + prop2: int64; + } + op read(@path pathParam: string, @query queryParam: string, ...Foo): OkResponse; + `; + const modelFile = await emitModularModelsFromTypeSpec(tspContent); + assert.ok(modelFile); + assertEqualContent( + modelFile?.getFullText()!, + ` + export interface Foo { + prop1: string; + prop2: number; + prop3: Date; + prop4: string; + prop5: Bar; + } + + export interface Bar { + prop1: string; + prop2: number; + }` + ); + const operationFiles = await emitModularOperationsFromTypeSpec(tspContent); + assert.ok(operationFiles); + assert.equal(operationFiles?.length, 1); + assertEqualContent( + operationFiles?.[0]?.getFullText()!, + ` + import { TestingContext as Client } from "../rest/index.js"; + import { + StreamableMethod, + operationOptionsToRequestParameters, + } from "@azure-rest/core-client"; + export function _readSend( + context: Client, + pathParam: string, + queryParam: string, + body: Foo, + options: ReadOptions = { requestOptions: {} } + ): StreamableMethod { + return context + .path("/{pathParam}", pathParam) + .post({ + ...operationOptionsToRequestParameters(options), + queryParameters: { queryParam: queryParam }, + body: { + prop1: body["prop1"], + prop2: body["prop2"], + prop3: body["prop3"].toISOString(), + prop4: body["prop4"], + prop5: { prop1: body.prop5["prop1"], prop2: body.prop5["prop2"] }, + }, + }); + } + export async function _readDeserialize(result: Read200Response): Promise { + if (result.status !== "200") { + throw result.body; + } + return; + } + export async function read( + context: Client, + pathParam: string, + queryParam: string, + body: Foo, + options: ReadOptions = { requestOptions: {} } + ): Promise { + const result = await _readSend( + context, + pathParam, + queryParam, + body, + options + ); + return _readDeserialize(result); + }`, + true + ); + }); +}); diff --git a/packages/typespec-ts/test/util/emitUtil.ts b/packages/typespec-ts/test/util/emitUtil.ts index 432ceede3e..d650656937 100644 --- a/packages/typespec-ts/test/util/emitUtil.ts +++ b/packages/typespec-ts/test/util/emitUtil.ts @@ -24,7 +24,7 @@ import { getRLCClients } from "../../src/utils/clientUtils.js"; import { expectDiagnosticEmpty } from "@typespec/compiler/testing"; import { transformHelperFunctionDetails } from "../../src/transform/transformHelperFunctionDetails.js"; import { emitCodeModel } from "../../src/modular/buildCodeModel.js"; -import { buildModels } from "../../src/modular/emitModels.js"; +import { buildModels, buildModelsOptions } from "../../src/modular/emitModels.js"; import { buildOperationFiles } from "../../src/modular/buildOperations.js"; import { Project } from "ts-morph"; @@ -213,7 +213,7 @@ export async function getRLCClientsFromTypeSpec(tspContent: string) { return clients; } -export async function emitModularModelsFromTypeSpec(tspContent: string) { +export async function emitModularModelsFromTypeSpec(tspContent: string, needOptions: boolean = false) { const context = await rlcEmitterFor(tspContent, true); const dpgContext = createDpgContextTestHelper(context.program); const serviceNameToRlcModelsMap: Map = new Map< @@ -241,6 +241,9 @@ export async function emitModularModelsFromTypeSpec(tspContent: string) { modularCodeModel.clients.length > 0 && modularCodeModel.clients[0] ) { + if (needOptions) { + return buildModelsOptions(modularCodeModel, modularCodeModel.clients[0]); + } return buildModels(modularCodeModel, modularCodeModel.clients[0]); } } @@ -276,10 +279,14 @@ export async function emitModularOperationsFromTypeSpec(tspContent: string) { modularCodeModel.clients.length > 0 && modularCodeModel.clients[0] ) { - return buildOperationFiles(dpgContext, modularCodeModel, modularCodeModel.clients[0], false); + return buildOperationFiles( + dpgContext, + modularCodeModel, + modularCodeModel.clients[0], + false + ); } } expectDiagnosticEmpty(dpgContext.program.diagnostics); return undefined; - -} \ No newline at end of file +}