From 6bcb7a7153d9bb19b82105bd57779097c6f6cca8 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Thu, 17 Aug 2023 11:01:57 +0800 Subject: [PATCH 01/16] Enable the azure core basic test for modular --- .../test/commands/cadl-ranch-list.ts | 7 +- .../generated/azure/core/.eslintrc.json | 11 + .../generated/azure/core/README.md | 56 +++ .../generated/azure/core/api-extractor.json | 18 + .../generated/azure/core/package.json | 97 +++++ .../generated/azure/core/rollup.config.js | 118 ++++++ .../generated/azure/core/src/BasicClient.ts | 90 +++++ .../azure/core/src/api/BasicContext.ts | 16 + .../generated/azure/core/src/api/index.ts | 17 + .../azure/core/src/api/operations.ts | 351 ++++++++++++++++++ .../generated/azure/core/src/index.ts | 18 + .../generated/azure/core/src/logger.ts | 5 + .../generated/azure/core/src/models/index.ts | 19 + .../generated/azure/core/src/models/models.ts | 47 +++ .../azure/core/src/models/options.ts | 42 +++ .../azure/core/src/rest/basicClient.ts | 35 ++ .../azure/core/src/rest/clientDefinitions.ts | 98 +++++ .../generated/azure/core/src/rest/index.ts | 16 + .../azure/core/src/rest/isUnexpected.ts | 169 +++++++++ .../generated/azure/core/src/rest/models.ts | 18 + .../azure/core/src/rest/outputModels.ts | 38 ++ .../azure/core/src/rest/paginateHelper.ts | 204 ++++++++++ .../azure/core/src/rest/parameters.ts | 57 +++ .../azure/core/src/rest/responses.ts | 141 +++++++ .../azure/core/src/rest/serializeHelper.ts | 13 + .../generated/azure/core/tsconfig.json | 27 ++ .../generated/azure/core/tspconfig.yaml | 14 + 27 files changed, 1741 insertions(+), 1 deletion(-) create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/.eslintrc.json create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/README.md create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/api-extractor.json create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/package.json create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/rollup.config.js create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/BasicClient.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/BasicContext.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/operations.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/logger.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/models.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/options.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/basicClient.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/clientDefinitions.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/isUnexpected.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/models.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/outputModels.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/paginateHelper.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/parameters.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/serializeHelper.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/tsconfig.json create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/tspconfig.yaml diff --git a/packages/typespec-ts/test/commands/cadl-ranch-list.ts b/packages/typespec-ts/test/commands/cadl-ranch-list.ts index c73884727a..faa6c59305 100644 --- a/packages/typespec-ts/test/commands/cadl-ranch-list.ts +++ b/packages/typespec-ts/test/commands/cadl-ranch-list.ts @@ -182,7 +182,7 @@ export const modularTsps: TypeSpecRanchConfig[] = [ }, { outputPath: "client/structure/default", - inputPath: "client/structure/default", + inputPath: "client/structure/default" }, { outputPath: "client/structure/multi-client", @@ -195,5 +195,10 @@ export const modularTsps: TypeSpecRanchConfig[] = [ { outputPath: "client/structure/two-operation-group", inputPath: "client/structure/two-operation-group" + }, + { + outputPath: "azure/core", + inputPath: "azure/core/basic", + debug: true } ]; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/.eslintrc.json b/packages/typespec-ts/test/modularIntegration/generated/azure/core/.eslintrc.json new file mode 100644 index 0000000000..619797ac39 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/.eslintrc.json @@ -0,0 +1,11 @@ +{ + "plugins": ["@azure/azure-sdk"], + "extends": ["plugin:@azure/azure-sdk/azure-sdk-base"], + "rules": { + "@azure/azure-sdk/ts-modules-only-named": "warn", + "@azure/azure-sdk/ts-apiextractor-json-types": "warn", + "@azure/azure-sdk/ts-package-json-types": "warn", + "@azure/azure-sdk/ts-package-json-engine-is-present": "warn", + "tsdoc/syntax": "warn" + } +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/README.md b/packages/typespec-ts/test/modularIntegration/generated/azure/core/README.md new file mode 100644 index 0000000000..054ee8680f --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/README.md @@ -0,0 +1,56 @@ +# Basic REST client library for JavaScript + +Illustrates bodies templated with Azure Core + +**Please rely heavily on our [REST client docs](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/rest-clients.md) to use this library** + +Key links: + +- [Package (NPM)](https://www.npmjs.com/package/@msinternal/azure-core-basic) + +## Getting started + +### Currently supported environments + +- LTS versions of Node.js + +### Prerequisites + +- You must have an [Azure subscription](https://azure.microsoft.com/free/) to use this package. + +### Install the `@msinternal/azure-core-basic` package + +Install the Basic REST client REST client library for JavaScript with `npm`: + +```bash +npm install @msinternal/azure-core-basic +``` + +### Create and authenticate a `BasicClient` + +To use an [Azure Active Directory (AAD) token credential](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/identity/identity/samples/AzureIdentityExamples.md#authenticating-with-a-pre-fetched-access-token), +provide an instance of the desired credential type obtained from the +[@azure/identity](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials) library. + +To authenticate with AAD, you must first `npm` install [`@azure/identity`](https://www.npmjs.com/package/@azure/identity) + +After setup, you can choose which type of [credential](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials) from `@azure/identity` to use. +As an example, [DefaultAzureCredential](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#defaultazurecredential) +can be used to authenticate the client. + +Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: +AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET + +## Troubleshooting + +### Logging + +Enabling logging may help uncover useful information about failures. In order to see a log of HTTP requests and responses, set the `AZURE_LOG_LEVEL` environment variable to `info`. Alternatively, logging can be enabled at runtime by calling `setLogLevel` in the `@azure/logger`: + +```javascript +const { setLogLevel } = require("@azure/logger"); + +setLogLevel("info"); +``` + +For more detailed instructions on how to enable logs, you can look at the [@azure/logger package docs](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger). diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/api-extractor.json b/packages/typespec-ts/test/modularIntegration/generated/azure/core/api-extractor.json new file mode 100644 index 0000000000..4d474dc76f --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/api-extractor.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "mainEntryPointFilePath": "./types/src/index.d.ts", + "docModel": { "enabled": true }, + "apiReport": { "enabled": true, "reportFolder": "./review" }, + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "", + "publicTrimmedFilePath": "./types/azure-core-basic.d.ts" + }, + "messages": { + "tsdocMessageReporting": { "default": { "logLevel": "none" } }, + "extractorMessageReporting": { + "ae-missing-release-tag": { "logLevel": "none" }, + "ae-unresolved-link": { "logLevel": "none" } + } + } +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/package.json b/packages/typespec-ts/test/modularIntegration/generated/azure/core/package.json new file mode 100644 index 0000000000..c79a03ffb6 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/package.json @@ -0,0 +1,97 @@ +{ + "name": "@msinternal/azure-core-basic", + "sdk-type": "client", + "author": "Microsoft Corporation", + "version": "1.0.0-beta.1", + "description": "Azure Core Basic Test Service", + "keywords": ["node", "azure", "cloud", "typescript", "browser", "isomorphic"], + "license": "MIT", + "type": "module", + "main": "dist/index.js", + "module": "./dist-esm/src/index.js", + "types": "./types/azure-core-basic.d.ts", + "exports": { + ".": { + "types": "./types/src/index.d.ts", + "require": "./dist/index.cjs", + "import": "./dist-esm/src/index.js" + }, + "./api": { + "types": "./types/src/api/index.d.ts", + "import": "./dist-esm/src/api/index.js" + }, + "./models": { + "types": "./types/src/models/index.d.ts", + "import": "./dist-esm/src/models/index.js" + } + }, + "repository": "github:Azure/azure-sdk-for-js", + "bugs": { "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, + "files": [ + "dist/", + "dist-esm/", + "types/azure-core-basic.d.ts", + "README.md", + "LICENSE", + "review/*" + ], + "engines": { "node": ">=14.0.0" }, + "scripts": { + "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", + "build:browser": "echo skipped.", + "build:node": "echo skipped.", + "build:samples": "echo skipped.", + "build:test": "echo skipped.", + "build:debug": "echo skipped.", + "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"*.{js,json}\" ", + "clean": "rimraf dist dist-browser dist-esm test-dist temp types *.tgz *.log", + "execute:samples": "echo skipped", + "extract-api": "rimraf review && mkdirp ./review && api-extractor run --local", + "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"*.{js,json}\" ", + "generate:client": "echo skipped", + "integration-test:browser": "echo skipped", + "integration-test:node": "echo skipped", + "integration-test": "echo skipped", + "lint:fix": "eslint package.json api-extractor.json src --ext .ts --fix --fix-type [problem,suggestion]", + "lint": "eslint package.json api-extractor.json src --ext .ts", + "pack": "npm pack 2>&1", + "test:browser": "echo skipped", + "test:node": "echo skipped", + "test": "echo \"Error: no test specified\" && exit 1", + "unit-test": "echo skipped", + "unit-test:node": "echo skipped", + "unit-test:browser": "echo skipped", + "build": "npm run clean && tsc && rollup -c 2>&1 && npm run minify && mkdirp ./review && npm run extract-api", + "minify": "uglifyjs -c -m --comments --source-map \"content='./dist/index.js.map'\" -o ./dist/index.min.js ./dist/index.js" + }, + "sideEffects": false, + "autoPublish": false, + "dependencies": { + "@azure/core-auth": "^1.3.0", + "@azure-rest/core-client": "^1.1.4", + "@azure/core-rest-pipeline": "^1.12.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.2.0", + "@azure/core-paging": "^1.5.0", + "@azure/core-util": "^1.4.0" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.31.1", + "autorest": "latest", + "@types/node": "^14.0.0", + "dotenv": "^16.0.0", + "eslint": "^8.0.0", + "mkdirp": "^2.1.2", + "prettier": "^2.5.1", + "rimraf": "^3.0.0", + "source-map-support": "^0.5.9", + "typescript": "~5.0.0", + "@rollup/plugin-commonjs": "^24.0.0", + "@rollup/plugin-json": "^6.0.0", + "@rollup/plugin-multi-entry": "^6.0.0", + "@rollup/plugin-node-resolve": "^13.1.3", + "rollup": "^2.66.1", + "rollup-plugin-sourcemaps": "^0.6.3", + "uglify-js": "^3.4.9" + } +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/rollup.config.js b/packages/typespec-ts/test/modularIntegration/generated/azure/core/rollup.config.js new file mode 100644 index 0000000000..61251d7a8d --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/rollup.config.js @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import nodeResolve from "@rollup/plugin-node-resolve"; +import cjs from "@rollup/plugin-commonjs"; +import sourcemaps from "rollup-plugin-sourcemaps"; +import multiEntry from "@rollup/plugin-multi-entry"; +import json from "@rollup/plugin-json"; + +import nodeBuiltins from "builtin-modules"; + +// #region Warning Handler + +/** + * A function that can determine whether a rollup warning should be ignored. If + * the function returns `true`, then the warning will not be displayed. + */ + +function ignoreNiseSinonEval(warning) { + return ( + warning.code === "EVAL" && + warning.id && + (warning.id.includes("node_modules/nise") || + warning.id.includes("node_modules/sinon")) === true + ); +} + +function ignoreChaiCircularDependency(warning) { + return ( + warning.code === "CIRCULAR_DEPENDENCY" && + warning.importer && + warning.importer.includes("node_modules/chai") === true + ); +} + +const warningInhibitors = [ignoreChaiCircularDependency, ignoreNiseSinonEval]; + +/** + * Construct a warning handler for the shared rollup configuration + * that ignores certain warnings that are not relevant to testing. + */ +function makeOnWarnForTesting() { + return (warning, warn) => { + // If every inhibitor returns false (i.e. no inhibitors), then show the warning + if (warningInhibitors.every((inhib) => !inhib(warning))) { + warn(warning); + } + }; +} + +// #endregion + +function makeBrowserTestConfig() { + const config = { + input: { + include: ["dist-esm/test/**/*.spec.js"], + exclude: ["dist-esm/test/**/node/**"], + }, + output: { + file: `dist-test/index.browser.js`, + format: "umd", + sourcemap: true, + }, + preserveSymlinks: false, + plugins: [ + multiEntry({ exports: false }), + nodeResolve({ + mainFields: ["module", "browser"], + }), + cjs(), + json(), + sourcemaps(), + //viz({ filename: "dist-test/browser-stats.html", sourcemap: true }) + ], + onwarn: makeOnWarnForTesting(), + // Disable tree-shaking of test code. In rollup-plugin-node-resolve@5.0.0, + // rollup started respecting the "sideEffects" field in package.json. Since + // our package.json sets "sideEffects=false", this also applies to test + // code, which causes all tests to be removed by tree-shaking. + treeshake: false, + }; + + return config; +} + +const defaultConfigurationOptions = { + disableBrowserBundle: false, +}; + +export function makeConfig(pkg, options) { + options = { + ...defaultConfigurationOptions, + ...(options || {}), + }; + + const baseConfig = { + // Use the package's module field if it has one + input: pkg["module"] || "dist-esm/src/index.js", + external: [ + ...nodeBuiltins, + ...Object.keys(pkg.dependencies), + ...Object.keys(pkg.devDependencies), + ], + output: { file: "dist/index.js", format: "cjs", sourcemap: true }, + preserveSymlinks: false, + plugins: [sourcemaps(), nodeResolve()], + }; + + const config = [baseConfig]; + + if (!options.disableBrowserBundle) { + config.push(makeBrowserTestConfig()); + } + + return config; +} + +export default makeConfig(require("./package.json")); 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 new file mode 100644 index 0000000000..aee4554c7b --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/BasicClient.ts @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { User, CustomPageModel, CustomPage, Page } from "./models/models.js"; +import { + CreateOrUpdateOptions, + CreateOrReplaceOptions, + GetOptions, + ListOptions, + ListWithPageOptions, + ListWithCustomPageModelOptions, + DeleteOptions, +} from "./models/options.js"; +import { + createBasic, + BasicClientOptions, + BasicContext, + createOrUpdate, + createOrReplace, + get, + list, + listWithPage, + listWithCustomPageModel, + deleteOperation, +} from "./api/index.js"; + +export { BasicClientOptions } from "./api/BasicContext.js"; + +export class BasicClient { + private _client: BasicContext; + + /** Illustrates bodies templated with Azure Core */ + constructor(options: BasicClientOptions = {}) { + this._client = createBasic(options); + } + + /** Creates or updates a User */ + createOrUpdate( + name: string, + id: number, + options: CreateOrUpdateOptions = { requestOptions: {} } + ): Promise { + return createOrUpdate(this._client, name, id, options); + } + + /** Creates or replaces a User */ + createOrReplace( + name: string, + id: number, + options: CreateOrReplaceOptions = { requestOptions: {} } + ): Promise { + return createOrReplace(this._client, name, id, options); + } + + /** Gets a User */ + get(id: number, options: GetOptions = { requestOptions: {} }): Promise { + return get(this._client, id, options); + } + + /** Lists all Users */ + list(options: ListOptions = { requestOptions: {} }): Promise { + return list(this._client, options); + } + + /** List with Azure.Core.Page<>. */ + listWithPage( + options: ListWithPageOptions = { requestOptions: {} } + ): Promise { + return listWithPage(this._client, options); + } + + /** List with custom page model. */ + listWithCustomPageModel( + options: ListWithCustomPageModelOptions = { requestOptions: {} } + ): Promise { + return listWithCustomPageModel(this._client, options); + } + + /** Deletes a User */ + /** + * @fixme delete is a reserved word that cannot be used as an operation name. Please add @projectedName( + * "javascript", "") to the operation to override the generated name. + */ + deleteOperation( + id: number, + options: DeleteOptions = { requestOptions: {} } + ): Promise { + return deleteOperation(this._client, id, options); + } +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/BasicContext.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/BasicContext.ts new file mode 100644 index 0000000000..93d746aa21 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/BasicContext.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { ClientOptions } from "@azure-rest/core-client"; +import { BasicContext } from "../rest/index.js"; +import getClient from "../rest/index.js"; + +export interface BasicClientOptions extends ClientOptions {} + +export { BasicContext } from "../rest/index.js"; + +/** Illustrates bodies templated with Azure Core */ +export function createBasic(options: BasicClientOptions = {}): BasicContext { + const clientContext = getClient(options); + return clientContext; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/index.ts new file mode 100644 index 0000000000..3ca24c50ad --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/index.ts @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { + createBasic, + BasicClientOptions, + BasicContext, +} from "./BasicContext.js"; +export { + createOrUpdate, + createOrReplace, + get, + list, + listWithPage, + listWithCustomPageModel, + deleteOperation, +} from "./operations.js"; 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 new file mode 100644 index 0000000000..d40bf24611 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/operations.ts @@ -0,0 +1,351 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { User, CustomPageModel, CustomPage, Page } from "../models/models.js"; +import { + isUnexpected, + BasicContext as Client, + CreateOrReplace200Response, + CreateOrReplace201Response, + CreateOrReplaceDefaultResponse, + CreateOrUpdate200Response, + CreateOrUpdate201Response, + CreateOrUpdateDefaultResponse, + DeleteOperation204Response, + DeleteOperationDefaultResponse, + Get200Response, + GetDefaultResponse, + List200Response, + ListDefaultResponse, + ListWithCustomPageModel200Response, + ListWithCustomPageModelDefaultResponse, + ListWithPage200Response, + ListWithPageDefaultResponse, +} from "../rest/index.js"; +import { + StreamableMethod, + operationOptionsToRequestParameters, +} from "@azure-rest/core-client"; +import { + CreateOrUpdateOptions, + CreateOrReplaceOptions, + GetOptions, + ListOptions, + ListWithPageOptions, + ListWithCustomPageModelOptions, + DeleteOptions, +} from "../models/options.js"; + +export function _createOrUpdateSend( + context: Client, + name: string, + id: number, + options: CreateOrUpdateOptions = { requestOptions: {} } +): StreamableMethod< + | CreateOrUpdate200Response + | CreateOrUpdate201Response + | CreateOrUpdateDefaultResponse +> { + return context + .path("/azure/core/basic/users/{id}", id) + .patch({ + ...operationOptionsToRequestParameters(options), + contentType: + (options.contentType as any) ?? "application/merge-patch+json", + body: { name: name, orders: options?.orders }, + }); +} + +export async function _createOrUpdateDeserialize( + result: + | CreateOrUpdate200Response + | CreateOrUpdate201Response + | CreateOrUpdateDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + id: result.body["id"], + name: result.body["name"], + orders: (result.body["orders"] ?? []).map((p) => ({ + id: p["id"], + userId: p["userId"], + detail: p["detail"], + })), + etag: result.body["etag"], + }; +} + +/** Creates or updates a User */ +export async function createOrUpdate( + context: Client, + name: string, + id: number, + options: CreateOrUpdateOptions = { requestOptions: {} } +): Promise { + const result = await _createOrUpdateSend(context, name, id, options); + return _createOrUpdateDeserialize(result); +} + +export function _createOrReplaceSend( + context: Client, + name: string, + id: number, + options: CreateOrReplaceOptions = { requestOptions: {} } +): StreamableMethod< + | CreateOrReplace200Response + | CreateOrReplace201Response + | CreateOrReplaceDefaultResponse +> { + return context + .path("/azure/core/basic/users/{id}", id) + .put({ + ...operationOptionsToRequestParameters(options), + body: { name: name, orders: options?.orders }, + }); +} + +export async function _createOrReplaceDeserialize( + result: + | CreateOrReplace200Response + | CreateOrReplace201Response + | CreateOrReplaceDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + id: result.body["id"], + name: result.body["name"], + orders: (result.body["orders"] ?? []).map((p) => ({ + id: p["id"], + userId: p["userId"], + detail: p["detail"], + })), + etag: result.body["etag"], + }; +} + +/** Creates or replaces a User */ +export async function createOrReplace( + context: Client, + name: string, + id: number, + options: CreateOrReplaceOptions = { requestOptions: {} } +): Promise { + const result = await _createOrReplaceSend(context, name, id, options); + return _createOrReplaceDeserialize(result); +} + +export function _getSend( + context: Client, + id: number, + options: GetOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/azure/core/basic/users/{id}", id) + .get({ ...operationOptionsToRequestParameters(options) }); +} + +export async function _getDeserialize( + result: Get200Response | GetDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + id: result.body["id"], + name: result.body["name"], + orders: (result.body["orders"] ?? []).map((p) => ({ + id: p["id"], + userId: p["userId"], + detail: p["detail"], + })), + etag: result.body["etag"], + }; +} + +/** Gets a User */ +export async function get( + context: Client, + id: number, + options: GetOptions = { requestOptions: {} } +): Promise { + const result = await _getSend(context, id, options); + return _getDeserialize(result); +} + +export function _listSend( + context: Client, + options: ListOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/azure/core/basic/users") + .get({ + ...operationOptionsToRequestParameters(options), + queryParameters: { + top: options?.top, + skip: options?.skip, + maxpagesize: options?.maxpagesize, + orderby: options?.orderby, + filter: options?.filter, + select: options?.select, + expand: options?.expand, + }, + }); +} + +export async function _listDeserialize( + result: List200Response | ListDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + value: (result.body["value"] ?? []).map((p) => ({ + id: p["id"], + name: p["name"], + orders: (p["orders"] ?? []).map((p) => ({ + id: p["id"], + userId: p["userId"], + detail: p["detail"], + })), + etag: p["etag"], + })), + nextLink: result.body["nextLink"], + }; +} + +/** Lists all Users */ +export async function list( + context: Client, + options: ListOptions = { requestOptions: {} } +): Promise { + const result = await _listSend(context, options); + return _listDeserialize(result); +} + +export function _listWithPageSend( + context: Client, + options: ListWithPageOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/azure/core/basic/page") + .get({ ...operationOptionsToRequestParameters(options) }); +} + +export async function _listWithPageDeserialize( + result: ListWithPage200Response | ListWithPageDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + value: (result.body["value"] ?? []).map((p) => ({ + id: p["id"], + name: p["name"], + orders: (p["orders"] ?? []).map((p) => ({ + id: p["id"], + userId: p["userId"], + detail: p["detail"], + })), + etag: p["etag"], + })), + nextLink: result.body["nextLink"], + }; +} + +/** List with Azure.Core.Page<>. */ +export async function listWithPage( + context: Client, + options: ListWithPageOptions = { requestOptions: {} } +): Promise { + const result = await _listWithPageSend(context, options); + return _listWithPageDeserialize(result); +} + +export function _listWithCustomPageModelSend( + context: Client, + options: ListWithCustomPageModelOptions = { requestOptions: {} } +): StreamableMethod< + ListWithCustomPageModel200Response | ListWithCustomPageModelDefaultResponse +> { + return context + .path("/azure/core/basic/custom-page") + .get({ ...operationOptionsToRequestParameters(options) }); +} + +export async function _listWithCustomPageModelDeserialize( + result: + | ListWithCustomPageModel200Response + | ListWithCustomPageModelDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + items: (result.body["items"] ?? []).map((p) => ({ + id: p["id"], + name: p["name"], + orders: (p["orders"] ?? []).map((p) => ({ + id: p["id"], + userId: p["userId"], + detail: p["detail"], + })), + etag: p["etag"], + })), + nextLink: result.body["nextLink"], + }; +} + +/** List with custom page model. */ +export async function listWithCustomPageModel( + context: Client, + options: ListWithCustomPageModelOptions = { requestOptions: {} } +): Promise { + const result = await _listWithCustomPageModelSend(context, options); + return _listWithCustomPageModelDeserialize(result); +} + +export function _deleteOperationSend( + context: Client, + id: number, + options: DeleteOptions = { requestOptions: {} } +): StreamableMethod< + DeleteOperation204Response | DeleteOperationDefaultResponse +> { + return context + .path("/azure/core/basic/users/{id}", id) + .delete({ ...operationOptionsToRequestParameters(options) }); +} + +export async function _deleteOperationDeserialize( + result: DeleteOperation204Response | DeleteOperationDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return; +} + +/** Deletes a User */ +/** + * @fixme delete is a reserved word that cannot be used as an operation name. Please add @projectedName( + * "javascript", "") to the operation to override the generated name. + */ +export async function deleteOperation( + context: Client, + id: number, + options: DeleteOptions = { requestOptions: {} } +): Promise { + const result = await _deleteOperationSend(context, id, options); + return _deleteOperationDeserialize(result); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts new file mode 100644 index 0000000000..cc437fbf34 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { BasicClient, BasicClientOptions } from "./BasicClient.js"; +export { + User, + UserOrder, + CustomPageModel, + CustomPage, + Page, + CreateOrUpdateOptions, + CreateOrReplaceOptions, + GetOptions, + ListOptions, + ListWithPageOptions, + ListWithCustomPageModelOptions, + DeleteOptions, +} from "./models/index.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/logger.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/logger.ts new file mode 100644 index 0000000000..d164bfc584 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/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("azure-core-basic"); diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts new file mode 100644 index 0000000000..7acd9996de --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { + User, + UserOrder, + CustomPageModel, + CustomPage, + Page, +} from "./models.js"; +export { + CreateOrUpdateOptions, + CreateOrReplaceOptions, + GetOptions, + ListOptions, + ListWithPageOptions, + ListWithCustomPageModelOptions, + DeleteOptions, +} from "./options.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/models.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/models.ts new file mode 100644 index 0000000000..2554e6564e --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/models.ts @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** Details about a user. */ +export interface User { + /** The user's id. */ + readonly id: number; + /** The user's name. */ + name: string; + /** The user's order list */ + orders?: UserOrder[]; + /** The entity tag for this resource. */ + readonly etag: string; +} + +/** UserOrder for testing list with expand. */ +export interface UserOrder { + /** The user's id. */ + readonly id: number; + /** The user's id. */ + userId: number; + /** The user's order detail */ + detail: string; +} + +export interface CustomPageModel { + /** List of items. */ + items: User[]; + /** Link to fetch more items. */ + nextLink?: string; +} + +/** Paged collection of User items */ +export interface CustomPage { + /** The User items on this page */ + value: User[]; + /** The link to the next page of items */ + nextLink?: string; +} + +/** Paged collection of User items */ +export interface Page { + /** The User items on this page */ + value: User[]; + /** The link to the next page of items */ + nextLink?: string; +} 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 new file mode 100644 index 0000000000..2c4cb79d74 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/options.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// 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 GetOptions extends OperationOptions {} + +export interface ListOptions extends OperationOptions { + /** The number of result items to return. */ + top?: number; + /** The number of result items to skip. */ + skip?: number; + /** The maximum number of result items per page. */ + maxpagesize?: number; + /** Expressions that specify the order of returned results. */ + orderby?: string[]; + /** Filter the result list using the given expression. */ + filter?: string; + /** Select the specified fields to be included in the response. */ + select?: string[]; + /** Expand the indicated resources into the response. */ + expand?: string[]; +} + +export interface ListWithPageOptions extends OperationOptions {} + +export interface ListWithCustomPageModelOptions extends OperationOptions {} + +export interface DeleteOptions extends OperationOptions {} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/basicClient.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/basicClient.ts new file mode 100644 index 0000000000..68441cc2e6 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/basicClient.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 { BasicContext } from "./clientDefinitions.js"; + +/** + * Initialize a new instance of `BasicContext` + * @param options - the parameter for all optional parameters + */ +export default function createClient( + options: ClientOptions = {} +): BasicContext { + const baseUrl = options.baseUrl ?? `http://localhost:3000`; + options.apiVersion = options.apiVersion ?? "2022-12-01-preview"; + const userAgentInfo = `azsdk-js-azure-core-basic-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 BasicContext; + + return client; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/clientDefinitions.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/clientDefinitions.ts new file mode 100644 index 0000000000..9fd4dedd67 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/clientDefinitions.ts @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + CreateOrUpdateParameters, + CreateOrReplaceParameters, + GetParameters, + DeleteParameters, + ListParameters, + ListWithPageParameters, + ListWithCustomPageModelParameters, +} from "./parameters.js"; +import { + CreateOrUpdate200Response, + CreateOrUpdate201Response, + CreateOrUpdateDefaultResponse, + CreateOrReplace200Response, + CreateOrReplace201Response, + CreateOrReplaceDefaultResponse, + Get200Response, + GetDefaultResponse, + DeleteOperation204Response, + DeleteOperationDefaultResponse, + List200Response, + ListDefaultResponse, + ListWithPage200Response, + ListWithPageDefaultResponse, + ListWithCustomPageModel200Response, + ListWithCustomPageModelDefaultResponse, +} from "./responses.js"; +import { Client, StreamableMethod } from "@azure-rest/core-client"; + +export interface CreateOrUpdate { + /** Creates or updates a User */ + patch( + options: CreateOrUpdateParameters + ): StreamableMethod< + | CreateOrUpdate200Response + | CreateOrUpdate201Response + | CreateOrUpdateDefaultResponse + >; + /** Creates or replaces a User */ + put( + options: CreateOrReplaceParameters + ): StreamableMethod< + | CreateOrReplace200Response + | CreateOrReplace201Response + | CreateOrReplaceDefaultResponse + >; + /** Gets a User */ + get( + options?: GetParameters + ): StreamableMethod; + /** Deletes a User */ + delete( + options?: DeleteParameters + ): StreamableMethod< + DeleteOperation204Response | DeleteOperationDefaultResponse + >; +} + +export interface List { + /** Lists all Users */ + get( + options?: ListParameters + ): StreamableMethod; +} + +export interface ListWithPage { + /** List with Azure.Core.Page<>. */ + get( + options?: ListWithPageParameters + ): StreamableMethod; +} + +export interface ListWithCustomPageModel { + /** List with custom page model. */ + get( + options?: ListWithCustomPageModelParameters + ): StreamableMethod< + ListWithCustomPageModel200Response | ListWithCustomPageModelDefaultResponse + >; +} + +export interface Routes { + /** Resource for '/azure/core/basic/users/\{id\}' has methods for the following verbs: patch, put, get, delete */ + (path: "/azure/core/basic/users/{id}", id: number): CreateOrUpdate; + /** Resource for '/azure/core/basic/users' has methods for the following verbs: get */ + (path: "/azure/core/basic/users"): List; + /** Resource for '/azure/core/basic/page' has methods for the following verbs: get */ + (path: "/azure/core/basic/page"): ListWithPage; + /** Resource for '/azure/core/basic/custom-page' has methods for the following verbs: get */ + (path: "/azure/core/basic/custom-page"): ListWithCustomPageModel; +} + +export type BasicContext = Client & { + path: Routes; +}; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/index.ts new file mode 100644 index 0000000000..8e6835c5e6 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/index.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import BasicClient from "./basicClient.js"; + +export * from "./basicClient.js"; +export * from "./parameters.js"; +export * from "./responses.js"; +export * from "./clientDefinitions.js"; +export * from "./isUnexpected.js"; +export * from "./models.js"; +export * from "./outputModels.js"; +export * from "./paginateHelper.js"; +export * from "./serializeHelper.js"; + +export default BasicClient; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/isUnexpected.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/isUnexpected.ts new file mode 100644 index 0000000000..b280ed685f --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/isUnexpected.ts @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + CreateOrUpdate200Response, + CreateOrUpdate201Response, + CreateOrUpdateDefaultResponse, + CreateOrReplace200Response, + CreateOrReplace201Response, + CreateOrReplaceDefaultResponse, + Get200Response, + GetDefaultResponse, + DeleteOperation204Response, + DeleteOperationDefaultResponse, + List200Response, + ListDefaultResponse, + ListWithPage200Response, + ListWithPageDefaultResponse, + ListWithCustomPageModel200Response, + ListWithCustomPageModelDefaultResponse, +} from "./responses.js"; + +const responseMap: Record = { + "PATCH /azure/core/basic/users/{id}": ["200", "201"], + "PUT /azure/core/basic/users/{id}": ["200", "201"], + "GET /azure/core/basic/users/{id}": ["200"], + "DELETE /azure/core/basic/users/{id}": ["204"], + "GET /azure/core/basic/users": ["200"], + "GET /azure/core/basic/page": ["200"], + "GET /azure/core/basic/custom-page": ["200"], +}; + +export function isUnexpected( + response: + | CreateOrUpdate200Response + | CreateOrUpdate201Response + | CreateOrUpdateDefaultResponse +): response is CreateOrUpdateDefaultResponse; +export function isUnexpected( + response: + | CreateOrReplace200Response + | CreateOrReplace201Response + | CreateOrReplaceDefaultResponse +): response is CreateOrReplaceDefaultResponse; +export function isUnexpected( + response: Get200Response | GetDefaultResponse +): response is GetDefaultResponse; +export function isUnexpected( + response: DeleteOperation204Response | DeleteOperationDefaultResponse +): response is DeleteOperationDefaultResponse; +export function isUnexpected( + response: List200Response | ListDefaultResponse +): response is ListDefaultResponse; +export function isUnexpected( + response: ListWithPage200Response | ListWithPageDefaultResponse +): response is ListWithPageDefaultResponse; +export function isUnexpected( + response: + | ListWithCustomPageModel200Response + | ListWithCustomPageModelDefaultResponse +): response is ListWithCustomPageModelDefaultResponse; +export function isUnexpected( + response: + | CreateOrUpdate200Response + | CreateOrUpdate201Response + | CreateOrUpdateDefaultResponse + | CreateOrReplace200Response + | CreateOrReplace201Response + | CreateOrReplaceDefaultResponse + | Get200Response + | GetDefaultResponse + | DeleteOperation204Response + | DeleteOperationDefaultResponse + | List200Response + | ListDefaultResponse + | ListWithPage200Response + | ListWithPageDefaultResponse + | ListWithCustomPageModel200Response + | ListWithCustomPageModelDefaultResponse +): response is + | CreateOrUpdateDefaultResponse + | CreateOrReplaceDefaultResponse + | GetDefaultResponse + | DeleteOperationDefaultResponse + | ListDefaultResponse + | ListWithPageDefaultResponse + | ListWithCustomPageModelDefaultResponse { + const lroOriginal = response.headers["x-ms-original-url"]; + const url = new URL(lroOriginal ?? response.request.url); + const method = response.request.method; + let pathDetails = responseMap[`${method} ${url.pathname}`]; + if (!pathDetails) { + pathDetails = getParametrizedPathSuccess(method, url.pathname); + } + return !pathDetails.includes(response.status); +} + +function getParametrizedPathSuccess(method: string, path: string): string[] { + const pathParts = path.split("/"); + + // Traverse list to match the longest candidate + // matchedLen: the length of candidate path + // matchedValue: the matched status code array + let matchedLen = -1, + matchedValue: string[] = []; + + // Iterate the responseMap to find a match + for (const [key, value] of Object.entries(responseMap)) { + // Extracting the path from the map key which is in format + // GET /path/foo + if (!key.startsWith(method)) { + continue; + } + const candidatePath = getPathFromMapKey(key); + // Get each part of the url path + const candidateParts = candidatePath.split("/"); + + // track if we have found a match to return the values found. + let found = true; + for ( + let i = candidateParts.length - 1, j = pathParts.length - 1; + i >= 1 && j >= 1; + i--, j-- + ) { + if ( + candidateParts[i]?.startsWith("{") && + candidateParts[i]?.indexOf("}") !== -1 + ) { + const start = candidateParts[i]!.indexOf("}") + 1, + end = candidateParts[i]?.length; + // If the current part of the candidate is a "template" part + // Try to use the suffix of pattern to match the path + // {guid} ==> $ + // {guid}:export ==> :export$ + const isMatched = new RegExp( + `${candidateParts[i]?.slice(start, end)}` + ).test(pathParts[j] || ""); + + if (!isMatched) { + found = false; + break; + } + continue; + } + + // If the candidate part is not a template and + // the parts don't match mark the candidate as not found + // to move on with the next candidate path. + if (candidateParts[i] !== pathParts[j]) { + found = false; + break; + } + } + + // We finished evaluating the current candidate parts + // Update the matched value if and only if we found the longer pattern + if (found && candidatePath.length > matchedLen) { + matchedLen = candidatePath.length; + matchedValue = value; + } + } + + return matchedValue; +} + +function getPathFromMapKey(mapKey: string): string { + const pathStart = mapKey.indexOf("/"); + return mapKey.slice(pathStart); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/models.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/models.ts new file mode 100644 index 0000000000..62d6eeda05 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/models.ts @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** Details about a user. */ +export interface User { + /** The user's name. */ + name: string; + /** The user's order list */ + orders?: Array; +} + +/** UserOrder for testing list with expand. */ +export interface UserOrder { + /** The user's id. */ + userId: number; + /** The user's order detail */ + detail: string; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/outputModels.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/outputModels.ts new file mode 100644 index 0000000000..fdba810e47 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/outputModels.ts @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Paged } from "@azure/core-paging"; + +/** Details about a user. */ +export interface UserOutput { + /** The user's id. */ + readonly id: number; + /** The user's name. */ + name: string; + /** The user's order list */ + orders?: Array; + /** The entity tag for this resource. */ + readonly etag: string; +} + +/** UserOrder for testing list with expand. */ +export interface UserOrderOutput { + /** The user's id. */ + readonly id: number; + /** The user's id. */ + userId: number; + /** The user's order detail */ + detail: string; +} + +export interface UserListResultsOutput { + /** List of items. */ + items: Array; + /** Link to fetch more items. */ + nextLink?: string; +} + +/** Paged collection of User items */ +export type UserListOutput = Paged; +/** Paged collection of User items */ +export type PagedUserOutput = Paged; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/paginateHelper.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/paginateHelper.ts new file mode 100644 index 0000000000..0f452b2c3e --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/paginateHelper.ts @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + getPagedAsyncIterator, + PagedAsyncIterableIterator, + PagedResult, +} from "@azure/core-paging"; +import { + Client, + createRestError, + PathUncheckedResponse, +} from "@azure-rest/core-client"; + +/** + * Helper type to extract the type of an array + */ +export type GetArrayType = T extends Array ? TData : never; + +/** + * The type of a custom function that defines how to get a page and a link to the next one if any. + */ +export type GetPage = ( + pageLink: string, + maxPageSize?: number +) => Promise<{ + page: TPage; + nextPageLink?: string; +}>; + +/** + * Options for the paging helper + */ +export interface PagingOptions { + /** + * Custom function to extract pagination details for crating the PagedAsyncIterableIterator + */ + customGetPage?: GetPage[]>; +} + +/** + * Helper type to infer the Type of the paged elements from the response type + * This type is generated based on the swagger information for x-ms-pageable + * specifically on the itemName property which indicates the property of the response + * where the page items are found. The default value is `value`. + * This type will allow us to provide strongly typed Iterator based on the response we get as second parameter + */ +export type PaginateReturn = TResult extends + | { + body: { value?: infer TPage }; + } + | { + body: { items?: infer TPage }; + } + ? GetArrayType + : Array; + +/** + * Helper to paginate results from an initial response that follows the specification of Autorest `x-ms-pageable` extension + * @param client - Client to use for sending the next page requests + * @param initialResponse - Initial response containing the nextLink and current page of elements + * @param customGetPage - Optional - Function to define how to extract the page and next link to be used to paginate the results + * @returns - PagedAsyncIterableIterator to iterate the elements + */ +export function paginate( + client: Client, + initialResponse: TResponse, + options: PagingOptions = {} +): PagedAsyncIterableIterator> { + // Extract element type from initial response + type TElement = PaginateReturn; + let firstRun = true; + // We need to check the response for success before trying to inspect it looking for + // the properties to use for nextLink and itemName + checkPagingRequest(initialResponse); + const { itemName, nextLinkName } = getPaginationProperties(initialResponse); + const { customGetPage } = options; + const pagedResult: PagedResult = { + firstPageLink: "", + getPage: + typeof customGetPage === "function" + ? customGetPage + : async (pageLink: string) => { + const result = firstRun + ? initialResponse + : await client.pathUnchecked(pageLink).get(); + firstRun = false; + checkPagingRequest(result); + const nextLink = getNextLink(result.body, nextLinkName); + const values = getElements(result.body, itemName); + return { + page: values, + nextPageLink: nextLink, + }; + }, + }; + + return getPagedAsyncIterator(pagedResult); +} + +/** + * Gets for the value of nextLink in the body + */ +function getNextLink(body: unknown, nextLinkName?: string): string | undefined { + if (!nextLinkName) { + return undefined; + } + + const nextLink = (body as Record)[nextLinkName]; + + if (typeof nextLink !== "string" && typeof nextLink !== "undefined") { + throw new Error( + `Body Property ${nextLinkName} should be a string or undefined` + ); + } + + return nextLink; +} + +/** + * Gets the elements of the current request in the body. + */ +function getElements(body: unknown, itemName: string): T[] { + const value = (body as Record)[itemName] as T[]; + + // value has to be an array according to the x-ms-pageable extension. + // The fact that this must be an array is used above to calculate the + // type of elements in the page in PaginateReturn + if (!Array.isArray(value)) { + throw new Error( + `Couldn't paginate response\n Body doesn't contain an array property with name: ${itemName}` + ); + } + + return value ?? []; +} + +/** + * Checks if a request failed + */ +function checkPagingRequest(response: PathUncheckedResponse): void { + const Http2xxStatusCodes = [ + "200", + "201", + "202", + "203", + "204", + "205", + "206", + "207", + "208", + "226", + ]; + if (!Http2xxStatusCodes.includes(response.status)) { + throw createRestError( + `Pagination failed with unexpected statusCode ${response.status}`, + response + ); + } +} + +/** + * Extracts the itemName and nextLinkName from the initial response to use them for pagination + */ +function getPaginationProperties(initialResponse: PathUncheckedResponse) { + // Build a set with the passed custom nextLinkNames + const nextLinkNames = new Set(["nextLink"]); + + // Build a set with the passed custom set of itemNames + const itemNames = new Set(["value", "items"]); + + let nextLinkName: string | undefined; + let itemName: string | undefined; + + for (const name of nextLinkNames) { + const nextLink = (initialResponse.body as Record)[ + name + ] as string; + if (nextLink) { + nextLinkName = name; + break; + } + } + + for (const name of itemNames) { + const item = (initialResponse.body as Record)[ + name + ] as string; + if (item) { + itemName = name; + break; + } + } + + if (!itemName) { + throw new Error( + `Couldn't paginate response\n Body doesn't contain an array property with name: ${[ + ...itemNames, + ].join(" OR ")}` + ); + } + + return { itemName, nextLinkName }; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/parameters.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/parameters.ts new file mode 100644 index 0000000000..b584d7ad4b --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/parameters.ts @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { RequestParameters } from "@azure-rest/core-client"; +import { User } from "./models.js"; + +/** The resource instance. */ +export type UserResourceMergeAndPatch = Partial; + +export interface CreateOrUpdateBodyParam { + /** The resource instance. */ + body: UserResourceMergeAndPatch; +} + +export interface CreateOrUpdateMediaTypesParam { + /** This request has a JSON Merge Patch body. */ + contentType: "application/merge-patch+json"; +} + +export type CreateOrUpdateParameters = CreateOrUpdateMediaTypesParam & + CreateOrUpdateBodyParam & + RequestParameters; + +export interface CreateOrReplaceBodyParam { + /** The resource instance. */ + body: User; +} + +export type CreateOrReplaceParameters = CreateOrReplaceBodyParam & + RequestParameters; +export type GetParameters = RequestParameters; + +export interface ListQueryParamProperties { + /** The number of result items to return. */ + top?: number; + /** The number of result items to skip. */ + skip?: number; + /** The maximum number of result items per page. */ + maxpagesize?: number; + /** Expressions that specify the order of returned results. This parameter needs to be formatted as multi collection, we provide buildMultiCollection from serializeHelper.ts to help, you will probably need to set skipUrlEncoding as true when sending the request */ + orderby?: string; + /** Filter the result list using the given expression. */ + filter?: string; + /** Select the specified fields to be included in the response. This parameter needs to be formatted as multi collection, we provide buildMultiCollection from serializeHelper.ts to help, you will probably need to set skipUrlEncoding as true when sending the request */ + select?: string; + /** Expand the indicated resources into the response. This parameter needs to be formatted as multi collection, we provide buildMultiCollection from serializeHelper.ts to help, you will probably need to set skipUrlEncoding as true when sending the request */ + expand?: string; +} + +export interface ListQueryParam { + queryParameters?: ListQueryParamProperties; +} + +export type ListParameters = ListQueryParam & RequestParameters; +export type ListWithPageParameters = RequestParameters; +export type ListWithCustomPageModelParameters = RequestParameters; +export type DeleteParameters = RequestParameters; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts new file mode 100644 index 0000000000..9611afb731 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { RawHttpHeaders } from "@azure/core-rest-pipeline"; +import { HttpResponse, ErrorResponse } from "@azure-rest/core-client"; +import { + UserOutput, + UserListOutput, + PagedUserOutput, + UserListResultsOutput, +} from "./outputModels.js"; + +/** The request has succeeded. */ +export interface CreateOrUpdate200Response extends HttpResponse { + status: "200"; + body: UserOutput; +} + +/** The request has succeeded and a new resource has been created as a result. */ +export interface CreateOrUpdate201Response extends HttpResponse { + status: "201"; + body: UserOutput; +} + +export interface CreateOrUpdateDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface CreateOrUpdateDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & CreateOrUpdateDefaultHeaders; +} + +/** The request has succeeded. */ +export interface CreateOrReplace200Response extends HttpResponse { + status: "200"; + body: UserOutput; +} + +/** The request has succeeded and a new resource has been created as a result. */ +export interface CreateOrReplace201Response extends HttpResponse { + status: "201"; + body: UserOutput; +} + +export interface CreateOrReplaceDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface CreateOrReplaceDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & CreateOrReplaceDefaultHeaders; +} + +/** The request has succeeded. */ +export interface Get200Response extends HttpResponse { + status: "200"; + body: UserOutput; +} + +export interface GetDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface GetDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & GetDefaultHeaders; +} + +/** The request has succeeded. */ +export interface List200Response extends HttpResponse { + status: "200"; + body: UserListOutput; +} + +export interface ListDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface ListDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & ListDefaultHeaders; +} + +/** The request has succeeded. */ +export interface ListWithPage200Response extends HttpResponse { + status: "200"; + body: PagedUserOutput; +} + +export interface ListWithPageDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface ListWithPageDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & ListWithPageDefaultHeaders; +} + +/** The request has succeeded. */ +export interface ListWithCustomPageModel200Response extends HttpResponse { + status: "200"; + body: UserListResultsOutput; +} + +export interface ListWithCustomPageModelDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface ListWithCustomPageModelDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & ListWithCustomPageModelDefaultHeaders; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface DeleteOperation204Response extends HttpResponse { + status: "204"; +} + +export interface DeleteOperationDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface DeleteOperationDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & DeleteOperationDefaultHeaders; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/serializeHelper.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/serializeHelper.ts new file mode 100644 index 0000000000..710a5bf2a7 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/serializeHelper.ts @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export function buildMultiCollection(items: string[], parameterName: string) { + return items + .map((item, index) => { + if (index === 0) { + return item; + } + return `${parameterName}=${item}`; + }) + .join("&"); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/tsconfig.json b/packages/typespec-ts/test/modularIntegration/generated/azure/core/tsconfig.json new file mode 100644 index 0000000000..d8b77d0227 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2017", + "module": "NodeNext", + "lib": ["esnext", "dom"], + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "sourceMap": true, + "importHelpers": true, + "strict": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "NodeNext", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "outDir": "./dist-esm", + "declarationDir": "./types", + "rootDir": "." + }, + "ts-node": { "esm": true }, + "include": ["./src/**/*.ts"] +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/tspconfig.yaml b/packages/typespec-ts/test/modularIntegration/generated/azure/core/tspconfig.yaml new file mode 100644 index 0000000000..6242bc0f31 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/tspconfig.yaml @@ -0,0 +1,14 @@ +emit: + - "@azure-tools/typespec-ts" +options: + "@azure-tools/typespec-ts": + "emitter-output-dir": "{project-root}" + generateMetadata: true + generateTest: false + addCredentials: false + azureSdkForJs: false + isCadlTest: true + isModularLibrary: true + packageDetails: + name: "@msinternal/azure-core-basic" + description: "Azure Core Basic Test Service" From 07aeb4975c8f63de4a151719d74657bbb4621448 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Thu, 17 Aug 2023 11:17:27 +0800 Subject: [PATCH 02/16] Resolve failure for export key word --- packages/rlc-common/src/helpers/nameUtils.ts | 2 +- .../generated/azure/core/src/BasicClient.ts | 15 ++++++ .../generated/azure/core/src/api/index.ts | 1 + .../azure/core/src/api/operations.ts | 53 +++++++++++++++++++ .../generated/azure/core/src/index.ts | 1 + .../generated/azure/core/src/models/index.ts | 1 + .../azure/core/src/models/options.ts | 2 + .../azure/core/src/rest/clientDefinitions.ts | 14 +++++ .../azure/core/src/rest/isUnexpected.ts | 11 +++- .../azure/core/src/rest/parameters.ts | 11 ++++ .../azure/core/src/rest/responses.ts | 17 ++++++ 11 files changed, 126 insertions(+), 2 deletions(-) diff --git a/packages/rlc-common/src/helpers/nameUtils.ts b/packages/rlc-common/src/helpers/nameUtils.ts index e5afc4416b..4764abdf9f 100644 --- a/packages/rlc-common/src/helpers/nameUtils.ts +++ b/packages/rlc-common/src/helpers/nameUtils.ts @@ -38,7 +38,7 @@ export const ReservedModelNames: ReservedName[] = [ { name: "else", reservedFor: [NameType.Parameter] }, { name: "enum", reservedFor: [NameType.Parameter] }, { name: "error", reservedFor: [NameType.Parameter, ...Newable] }, - { name: "export", reservedFor: [NameType.Parameter] }, + { name: "export", reservedFor: [NameType.Parameter, NameType.Operation] }, { name: "extends", reservedFor: [NameType.Parameter] }, { name: "false", reservedFor: [NameType.Parameter] }, { name: "finally", reservedFor: [NameType.Parameter] }, 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 aee4554c7b..c7beeafd12 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 @@ -10,6 +10,7 @@ import { ListWithPageOptions, ListWithCustomPageModelOptions, DeleteOptions, + ExportOptions, } from "./models/options.js"; import { createBasic, @@ -22,6 +23,7 @@ import { listWithPage, listWithCustomPageModel, deleteOperation, + exportOperation, } from "./api/index.js"; export { BasicClientOptions } from "./api/BasicContext.js"; @@ -87,4 +89,17 @@ export class BasicClient { ): Promise { return deleteOperation(this._client, id, options); } + + /** Exports a User */ + /** + * @fixme export is a reserved word that cannot be used as an operation name. Please add @projectedName( + * "javascript", "") to the operation to override the generated name. + */ + exportOperation( + id: number, + format: string, + options: ExportOptions = { requestOptions: {} } + ): Promise { + return exportOperation(this._client, id, format, options); + } } diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/index.ts index 3ca24c50ad..636a856252 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/api/index.ts @@ -14,4 +14,5 @@ export { listWithPage, listWithCustomPageModel, deleteOperation, + exportOperation, } from "./operations.js"; 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 d40bf24611..fe8cd73f4c 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 @@ -13,6 +13,8 @@ import { CreateOrUpdateDefaultResponse, DeleteOperation204Response, DeleteOperationDefaultResponse, + ExportOperation200Response, + ExportOperationDefaultResponse, Get200Response, GetDefaultResponse, List200Response, @@ -34,6 +36,7 @@ import { ListWithPageOptions, ListWithCustomPageModelOptions, DeleteOptions, + ExportOptions, } from "../models/options.js"; export function _createOrUpdateSend( @@ -349,3 +352,53 @@ export async function deleteOperation( const result = await _deleteOperationSend(context, id, options); return _deleteOperationDeserialize(result); } + +export function _exportOperationSend( + context: Client, + id: number, + format: string, + options: ExportOptions = { requestOptions: {} } +): StreamableMethod< + ExportOperation200Response | ExportOperationDefaultResponse +> { + return context + .path("/azure/core/basic/users/{id}:export", id) + .post({ + ...operationOptionsToRequestParameters(options), + queryParameters: { format: format }, + }); +} + +export async function _exportOperationDeserialize( + result: ExportOperation200Response | ExportOperationDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + id: result.body["id"], + name: result.body["name"], + orders: (result.body["orders"] ?? []).map((p) => ({ + id: p["id"], + userId: p["userId"], + detail: p["detail"], + })), + etag: result.body["etag"], + }; +} + +/** Exports a User */ +/** + * @fixme export is a reserved word that cannot be used as an operation name. Please add @projectedName( + * "javascript", "") to the operation to override the generated name. + */ +export async function exportOperation( + context: Client, + id: number, + format: string, + options: ExportOptions = { requestOptions: {} } +): Promise { + const result = await _exportOperationSend(context, id, format, options); + return _exportOperationDeserialize(result); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts index cc437fbf34..e6a6381fb3 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts @@ -15,4 +15,5 @@ export { ListWithPageOptions, ListWithCustomPageModelOptions, DeleteOptions, + ExportOptions, } from "./models/index.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts index 7acd9996de..4dd7d24afb 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts @@ -16,4 +16,5 @@ export { ListWithPageOptions, ListWithCustomPageModelOptions, DeleteOptions, + ExportOptions, } from "./options.js"; 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 2c4cb79d74..dc566023e1 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 @@ -40,3 +40,5 @@ export interface ListWithPageOptions extends OperationOptions {} export interface ListWithCustomPageModelOptions extends OperationOptions {} export interface DeleteOptions extends OperationOptions {} + +export interface ExportOptions extends OperationOptions {} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/clientDefinitions.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/clientDefinitions.ts index 9fd4dedd67..8a824b1399 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/clientDefinitions.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/clientDefinitions.ts @@ -9,6 +9,7 @@ import { ListParameters, ListWithPageParameters, ListWithCustomPageModelParameters, + ExportParameters, } from "./parameters.js"; import { CreateOrUpdate200Response, @@ -27,6 +28,8 @@ import { ListWithPageDefaultResponse, ListWithCustomPageModel200Response, ListWithCustomPageModelDefaultResponse, + ExportOperation200Response, + ExportOperationDefaultResponse, } from "./responses.js"; import { Client, StreamableMethod } from "@azure-rest/core-client"; @@ -82,6 +85,15 @@ export interface ListWithCustomPageModel { >; } +export interface Export { + /** Exports a User */ + post( + options: ExportParameters + ): StreamableMethod< + ExportOperation200Response | ExportOperationDefaultResponse + >; +} + export interface Routes { /** Resource for '/azure/core/basic/users/\{id\}' has methods for the following verbs: patch, put, get, delete */ (path: "/azure/core/basic/users/{id}", id: number): CreateOrUpdate; @@ -91,6 +103,8 @@ export interface Routes { (path: "/azure/core/basic/page"): ListWithPage; /** Resource for '/azure/core/basic/custom-page' has methods for the following verbs: get */ (path: "/azure/core/basic/custom-page"): ListWithCustomPageModel; + /** Resource for '/azure/core/basic/users/\{id\}:export' has methods for the following verbs: post */ + (path: "/azure/core/basic/users/{id}:export", id: number): Export; } export type BasicContext = Client & { diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/isUnexpected.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/isUnexpected.ts index b280ed685f..ad9c6e0bef 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/isUnexpected.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/isUnexpected.ts @@ -18,6 +18,8 @@ import { ListWithPageDefaultResponse, ListWithCustomPageModel200Response, ListWithCustomPageModelDefaultResponse, + ExportOperation200Response, + ExportOperationDefaultResponse, } from "./responses.js"; const responseMap: Record = { @@ -28,6 +30,7 @@ const responseMap: Record = { "GET /azure/core/basic/users": ["200"], "GET /azure/core/basic/page": ["200"], "GET /azure/core/basic/custom-page": ["200"], + "POST /azure/core/basic/users/{id}:export": ["200"], }; export function isUnexpected( @@ -59,6 +62,9 @@ export function isUnexpected( | ListWithCustomPageModel200Response | ListWithCustomPageModelDefaultResponse ): response is ListWithCustomPageModelDefaultResponse; +export function isUnexpected( + response: ExportOperation200Response | ExportOperationDefaultResponse +): response is ExportOperationDefaultResponse; export function isUnexpected( response: | CreateOrUpdate200Response @@ -77,6 +83,8 @@ export function isUnexpected( | ListWithPageDefaultResponse | ListWithCustomPageModel200Response | ListWithCustomPageModelDefaultResponse + | ExportOperation200Response + | ExportOperationDefaultResponse ): response is | CreateOrUpdateDefaultResponse | CreateOrReplaceDefaultResponse @@ -84,7 +92,8 @@ export function isUnexpected( | DeleteOperationDefaultResponse | ListDefaultResponse | ListWithPageDefaultResponse - | ListWithCustomPageModelDefaultResponse { + | ListWithCustomPageModelDefaultResponse + | ExportOperationDefaultResponse { const lroOriginal = response.headers["x-ms-original-url"]; const url = new URL(lroOriginal ?? response.request.url); const method = response.request.method; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/parameters.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/parameters.ts index b584d7ad4b..d54f8b1a61 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/parameters.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/parameters.ts @@ -55,3 +55,14 @@ export type ListParameters = ListQueryParam & RequestParameters; export type ListWithPageParameters = RequestParameters; export type ListWithCustomPageModelParameters = RequestParameters; export type DeleteParameters = RequestParameters; + +export interface ExportQueryParamProperties { + /** The format of the data. */ + format: string; +} + +export interface ExportQueryParam { + queryParameters: ExportQueryParamProperties; +} + +export type ExportParameters = ExportQueryParam & RequestParameters; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts index 9611afb731..ddd916eda0 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts @@ -139,3 +139,20 @@ export interface DeleteOperationDefaultResponse extends HttpResponse { body: ErrorResponse; headers: RawHttpHeaders & DeleteOperationDefaultHeaders; } + +/** The request has succeeded. */ +export interface ExportOperation200Response extends HttpResponse { + status: "200"; + body: UserOutput; +} + +export interface ExportOperationDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface ExportOperationDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & ExportOperationDefaultHeaders; +} From ecbb83f5e9f621feac4bee6fbe9546cbf176853d Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Fri, 18 Aug 2023 12:14:36 +0800 Subject: [PATCH 03/16] Manually update the compile error codes --- .../azure/core/src/api/operations.ts | 99 +++++++++---------- 1 file changed, 46 insertions(+), 53 deletions(-) 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 fe8cd73f4c..3de0a3a873 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 @@ -23,10 +23,11 @@ import { ListWithCustomPageModelDefaultResponse, ListWithPage200Response, ListWithPageDefaultResponse, + buildMultiCollection } from "../rest/index.js"; import { StreamableMethod, - operationOptionsToRequestParameters, + operationOptionsToRequestParameters } from "@azure-rest/core-client"; import { CreateOrUpdateOptions, @@ -36,7 +37,7 @@ import { ListWithPageOptions, ListWithCustomPageModelOptions, DeleteOptions, - ExportOptions, + ExportOptions } from "../models/options.js"; export function _createOrUpdateSend( @@ -49,14 +50,11 @@ export function _createOrUpdateSend( | CreateOrUpdate201Response | CreateOrUpdateDefaultResponse > { - return context - .path("/azure/core/basic/users/{id}", id) - .patch({ - ...operationOptionsToRequestParameters(options), - contentType: - (options.contentType as any) ?? "application/merge-patch+json", - body: { name: name, orders: options?.orders }, - }); + return context.path("/azure/core/basic/users/{id}", id).patch({ + ...operationOptionsToRequestParameters(options), + contentType: (options.contentType as any) ?? "application/merge-patch+json", + body: { name: name, orders: options?.orders } + }); } export async function _createOrUpdateDeserialize( @@ -75,9 +73,9 @@ export async function _createOrUpdateDeserialize( orders: (result.body["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"], + detail: p["detail"] })), - etag: result.body["etag"], + etag: result.body["etag"] }; } @@ -102,12 +100,10 @@ export function _createOrReplaceSend( | CreateOrReplace201Response | CreateOrReplaceDefaultResponse > { - return context - .path("/azure/core/basic/users/{id}", id) - .put({ - ...operationOptionsToRequestParameters(options), - body: { name: name, orders: options?.orders }, - }); + return context.path("/azure/core/basic/users/{id}", id).put({ + ...operationOptionsToRequestParameters(options), + body: { name: name, orders: options?.orders } + }); } export async function _createOrReplaceDeserialize( @@ -126,9 +122,9 @@ export async function _createOrReplaceDeserialize( orders: (result.body["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"], + detail: p["detail"] })), - etag: result.body["etag"], + etag: result.body["etag"] }; } @@ -166,9 +162,9 @@ export async function _getDeserialize( orders: (result.body["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"], + detail: p["detail"] })), - etag: result.body["etag"], + etag: result.body["etag"] }; } @@ -186,20 +182,19 @@ export function _listSend( context: Client, options: ListOptions = { requestOptions: {} } ): StreamableMethod { - return context - .path("/azure/core/basic/users") - .get({ - ...operationOptionsToRequestParameters(options), - queryParameters: { - top: options?.top, - skip: options?.skip, - maxpagesize: options?.maxpagesize, - orderby: options?.orderby, - filter: options?.filter, - select: options?.select, - expand: options?.expand, - }, - }); + return context.path("/azure/core/basic/users").get({ + ...operationOptionsToRequestParameters(options), + queryParameters: { + top: options?.top, + skip: options?.skip, + maxpagesize: options?.maxpagesize, + orderby: + options.orderby && buildMultiCollection(options.orderby, "orderBy"), + filter: options?.filter, + select: options.select && buildMultiCollection(options.select, "select"), + expand: options.expand && buildMultiCollection(options.expand, "expand") + } + }); } export async function _listDeserialize( @@ -216,11 +211,11 @@ export async function _listDeserialize( orders: (p["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"], + detail: p["detail"] })), - etag: p["etag"], + etag: p["etag"] })), - nextLink: result.body["nextLink"], + nextLink: result.body["nextLink"] }; } @@ -256,11 +251,11 @@ export async function _listWithPageDeserialize( orders: (p["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"], + detail: p["detail"] })), - etag: p["etag"], + etag: p["etag"] })), - nextLink: result.body["nextLink"], + nextLink: result.body["nextLink"] }; } @@ -300,11 +295,11 @@ export async function _listWithCustomPageModelDeserialize( orders: (p["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"], + detail: p["detail"] })), - etag: p["etag"], + etag: p["etag"] })), - nextLink: result.body["nextLink"], + nextLink: result.body["nextLink"] }; } @@ -361,12 +356,10 @@ export function _exportOperationSend( ): StreamableMethod< ExportOperation200Response | ExportOperationDefaultResponse > { - return context - .path("/azure/core/basic/users/{id}:export", id) - .post({ - ...operationOptionsToRequestParameters(options), - queryParameters: { format: format }, - }); + return context.path("/azure/core/basic/users/{id}:export", id).post({ + ...operationOptionsToRequestParameters(options), + queryParameters: { format: format } + }); } export async function _exportOperationDeserialize( @@ -382,9 +375,9 @@ export async function _exportOperationDeserialize( orders: (result.body["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"], + detail: p["detail"] })), - etag: result.body["etag"], + etag: result.body["etag"] }; } From a25c888a1d0deca8ff657267bde5b5ac9a9e78b9 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Fri, 18 Aug 2023 14:21:05 +0800 Subject: [PATCH 04/16] Build a separated generator function for paging function --- .../test/modularIntegration/azureCore.spec.ts | 26 ++++++ .../generated/azure/core/src/BasicClient.ts | 7 +- .../azure/core/src/api/operations.ts | 45 +++++++++- .../generated/azure/core/src/pageHelper.ts | 84 +++++++++++++++++++ 4 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 packages/typespec-ts/test/modularIntegration/azureCore.spec.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/pageHelper.ts diff --git a/packages/typespec-ts/test/modularIntegration/azureCore.spec.ts b/packages/typespec-ts/test/modularIntegration/azureCore.spec.ts new file mode 100644 index 0000000000..79e8657211 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/azureCore.spec.ts @@ -0,0 +1,26 @@ +import { BasicClient } from "./generated/azure/core/src/index.js"; +import { assert } from "chai"; + +describe.only("BasicClient Classical Client", () => { + let client: BasicClient; + + beforeEach(() => { + client = new BasicClient({ + allowInsecureConnection: true + }); + }); + + it("should list items with paging", async () => { + try { + const iter = client.listWithPage(); + const resArray = new Array(); + for await (let item of iter) { + resArray.push(item); + } + assert.strictEqual(resArray.length, 1); + } catch (err) { + console.log(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 c7beeafd12..e0fbc301d7 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 @@ -10,7 +10,7 @@ import { ListWithPageOptions, ListWithCustomPageModelOptions, DeleteOptions, - ExportOptions, + ExportOptions } from "./models/options.js"; import { createBasic, @@ -23,8 +23,9 @@ import { listWithPage, listWithCustomPageModel, deleteOperation, - exportOperation, + exportOperation } from "./api/index.js"; +import { PagedAsyncIterableIterator } from "@azure/core-paging"; export { BasicClientOptions } from "./api/BasicContext.js"; @@ -67,7 +68,7 @@ export class BasicClient { /** List with Azure.Core.Page<>. */ listWithPage( options: ListWithPageOptions = { requestOptions: {} } - ): Promise { + ): PagedAsyncIterableIterator { return listWithPage(this._client, options); } 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 3de0a3a873..8b92c62438 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 @@ -39,6 +39,16 @@ import { DeleteOptions, ExportOptions } from "../models/options.js"; +import { + PagedAsyncIterableIterator, + PagedResult, + getPagedAsyncIterator +} from "@azure/core-paging"; +import { + getElements, + getNextLink, + getPaginationProperties +} from "../pageHelper.js"; export function _createOrUpdateSend( context: Client, @@ -260,12 +270,39 @@ export async function _listWithPageDeserialize( } /** List with Azure.Core.Page<>. */ -export async function listWithPage( +export function listWithPage( context: Client, options: ListWithPageOptions = { requestOptions: {} } -): Promise { - const result = await _listWithPageSend(context, options); - return _listWithPageDeserialize(result); +): PagedAsyncIterableIterator { + return listWithPageGenerator(context, options); +} + +function listWithPageGenerator( + context: Client, + options: ListWithPageOptions +): PagedAsyncIterableIterator { + let firstRun = true; + const pagedResult: PagedResult = { + firstPageLink: "", + getPage: async (pageLink: string) => { + const result = firstRun + ? await _listWithPageSend(context, options) + : await context.pathUnchecked(pageLink).get(); + const { itemName, nextLinkName } = getPaginationProperties(result); + firstRun = false; + const nextLink = getNextLink(result.body, nextLinkName); + const values = getElements( + await _listWithPageDeserialize(result), + itemName + ); + return { + page: values, + nextPageLink: nextLink + }; + } + }; + + return getPagedAsyncIterator(pagedResult); } export function _listWithCustomPageModelSend( diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/pageHelper.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/pageHelper.ts new file mode 100644 index 0000000000..ecc65ce4cc --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/pageHelper.ts @@ -0,0 +1,84 @@ +import { PathUncheckedResponse } from "@azure-rest/core-client"; + +/** + * Gets for the value of nextLink in the body + */ +export function getNextLink( + body: unknown, + nextLinkName?: string +): string | undefined { + if (!nextLinkName) { + return undefined; + } + + const nextLink = (body as Record)[nextLinkName]; + + if (typeof nextLink !== "string" && typeof nextLink !== "undefined") { + throw new Error( + `Body Property ${nextLinkName} should be a string or undefined` + ); + } + + return nextLink; +} + +/** + * Gets the elements of the current request in the body. + */ +export function getElements(body: unknown, itemName: string): T[] { + const value = (body as Record)[itemName] as T[]; + + // value has to be an array according to the x-ms-pageable extension. + // The fact that this must be an array is used above to calculate the + // type of elements in the page in PaginateReturn + if (!Array.isArray(value)) { + throw new Error( + `Couldn't paginate response\n Body doesn't contain an array property with name: ${itemName}` + ); + } + + return value ?? []; +} + +export function getPaginationProperties( + initialResponse: PathUncheckedResponse +) { + // Build a set with the passed custom nextLinkNames + const nextLinkNames = new Set(["nextLink"]); + + // Build a set with the passed custom set of itemNames + const itemNames = new Set(["value", "items"]); + + let nextLinkName: string | undefined; + let itemName: string | undefined; + + for (const name of nextLinkNames) { + const nextLink = (initialResponse.body as Record)[ + name + ] as string; + if (nextLink) { + nextLinkName = name; + break; + } + } + + for (const name of itemNames) { + const item = (initialResponse.body as Record)[ + name + ] as string; + if (item) { + itemName = name; + break; + } + } + + if (!itemName) { + throw new Error( + `Couldn't paginate response\n Body doesn't contain an array property with name: ${[ + ...itemNames + ].join(" OR ")}` + ); + } + + return { itemName, nextLinkName }; +} From f58929b401d91e7c12e3652ceef9d74c6467e98e Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Fri, 18 Aug 2023 18:31:14 +0800 Subject: [PATCH 05/16] Update the debugging code --- .../typespec-ts/src/modular/buildCodeModel.ts | 3 +- .../src/modular/helpers/operationHelpers.ts | 41 ++++- .../src/modular/modularCodeModel.ts | 1 + .../transformHelperFunctionDetails.ts | 14 +- .../src/transform/transformParameters.ts | 62 +------ .../typespec-ts/src/utils/operationUtil.ts | 87 +++++++++ .../generated/azure/core/src/BasicClient.ts | 13 +- .../azure/core/src/api/operations.ts | 166 ++++++++---------- .../generated/azure/core/src/index.ts | 5 +- .../generated/azure/core/src/models/index.ts | 8 +- .../generated/azure/core/src/models/models.ts | 6 +- .../generated/azure/core/src/pageHelper.ts | 84 --------- .../azure/core/src/rest/outputModels.ts | 2 - .../azure/core/src/rest/responses.ts | 3 +- 14 files changed, 226 insertions(+), 269 deletions(-) delete mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core/src/pageHelper.ts diff --git a/packages/typespec-ts/src/modular/buildCodeModel.ts b/packages/typespec-ts/src/modular/buildCodeModel.ts index a702876b29..80797c0fc1 100644 --- a/packages/typespec-ts/src/modular/buildCodeModel.ts +++ b/packages/typespec-ts/src/modular/buildCodeModel.ts @@ -461,7 +461,8 @@ function emitParameter( location: parameter.type, type: type, implementation: implementation, - skipUrlEncoding: parameter.type === "endpointPath" + skipUrlEncoding: parameter.type === "endpointPath", + format: (parameter as any).format }; if (paramMap.type.type === "constant") { diff --git a/packages/typespec-ts/src/modular/helpers/operationHelpers.ts b/packages/typespec-ts/src/modular/helpers/operationHelpers.ts index f75ec0573b..cedacf8f2b 100644 --- a/packages/typespec-ts/src/modular/helpers/operationHelpers.ts +++ b/packages/typespec-ts/src/modular/helpers/operationHelpers.ts @@ -25,6 +25,10 @@ import { getFixmeForMultilineDocs, getDocsFromDescription } from "./docsHelpers.js"; +import { + getCollectionFormatFunction, + hasCollectionFormatInfo +} from "../../utils/operationUtil.js"; function getRLCResponseType(rlcResponse?: OperationResponse) { if (!rlcResponse?.responses) { @@ -395,6 +399,11 @@ function getParameterMap( return getConstantValue(param); } + if (hasCollectionFormatInfo((param as any).location, (param as any).format)) { + console.log(">>>>>>>>>>>>>>>>>hasCollectionFormatInfo", param); + return getCollectionFormatParamMap(param as Parameter, importSet); + } + // if the parameter or property is optional, we don't need to handle the default value if (isOptional(param)) { return getOptional(param, importSet); @@ -407,6 +416,29 @@ function getParameterMap( throw new Error(`Parameter ${param.clientName} is not supported`); } +function getCollectionFormatParamMap( + param: Parameter, + importSet: Map> +) { + const rlcUtilSet = importSet.get("../rest/index.js"); + const collectionInfo = getCollectionFormatFunction( + param.location, + param.format ?? "" + ); + console.log(">>>>>>>>>>>>>>>>>getCollectionFormatParamMap", collectionInfo); + if (!collectionInfo) { + throw "Has collection format info but without helper function detected"; + } + const isOptional = param.optional ? "options?." : ""; + const clientName = `${isOptional}${param.clientName}`; + if (!rlcUtilSet) { + importSet.set("../rest/index.js", new Set().add(collectionInfo)); + } else { + rlcUtilSet.add(collectionInfo); + } + return `"${param.restApiName}": ${clientName} !== undefined ? ${collectionInfo}(${clientName}, "${param.restApiName}"): undefined`; +} + function isContentType(param: Parameter): boolean { return ( param.location === "header" && @@ -477,16 +509,11 @@ type OptionalType = (Parameter | Property) & { type: { optional: true }; }; -function isOptional( - param: Parameter | Property -): param is OptionalType { +function isOptional(param: Parameter | Property): param is OptionalType { return Boolean(param.optional); } -function getOptional( - param: OptionalType, - importSet: Map> -) { +function getOptional(param: OptionalType, importSet: Map>) { if (param.type.type === "model") { return `"${param.restApiName}": {${getRequestModelMapping( param.type, diff --git a/packages/typespec-ts/src/modular/modularCodeModel.ts b/packages/typespec-ts/src/modular/modularCodeModel.ts index 16c606bc2f..a81d69724d 100644 --- a/packages/typespec-ts/src/modular/modularCodeModel.ts +++ b/packages/typespec-ts/src/modular/modularCodeModel.ts @@ -124,6 +124,7 @@ export interface Parameter { inDocstring?: boolean; inOverriden?: boolean; isApiVersion?: boolean; + format?: string; } export interface Response { diff --git a/packages/typespec-ts/src/transform/transformHelperFunctionDetails.ts b/packages/typespec-ts/src/transform/transformHelperFunctionDetails.ts index 4d8f14bb5e..e5eb6f9421 100644 --- a/packages/typespec-ts/src/transform/transformHelperFunctionDetails.ts +++ b/packages/typespec-ts/src/transform/transformHelperFunctionDetails.ts @@ -10,9 +10,9 @@ import { getHttpOperation, HttpOperation } from "@typespec/http"; import { hasPagingOperations, extractPagedMetadataNested, - hasPollingOperations + hasPollingOperations, + getSpecialSerializeInfo } from "../utils/operationUtil.js"; -import { getSpecialSerializeInfo } from "./transformParameters.js"; import { SdkContext } from "../utils/interfaces.js"; export function transformHelperFunctionDetails( @@ -199,7 +199,10 @@ function extractSpecialSerializeInfo( for (const op of operations) { const route = ignoreDiagnostics(getHttpOperation(program, op)); route.parameters.parameters.forEach((parameter) => { - const serializeInfo = getSpecialSerializeInfo(parameter); + const serializeInfo = getSpecialSerializeInfo( + parameter.type, + (parameter as any).format + ); hasMultiCollection = hasMultiCollection ? hasMultiCollection : serializeInfo.hasMultiCollection; @@ -222,7 +225,10 @@ function extractSpecialSerializeInfo( for (const clientOp of clientOperations) { const route = ignoreDiagnostics(getHttpOperation(program, clientOp)); route.parameters.parameters.forEach((parameter) => { - const serializeInfo = getSpecialSerializeInfo(parameter); + const serializeInfo = getSpecialSerializeInfo( + parameter.type, + (parameter as any).format + ); hasMultiCollection = hasMultiCollection ? hasMultiCollection : serializeInfo.hasMultiCollection; diff --git a/packages/typespec-ts/src/transform/transformParameters.ts b/packages/typespec-ts/src/transform/transformParameters.ts index 279bc4dbec..2dc6b93ee3 100644 --- a/packages/typespec-ts/src/transform/transformParameters.ts +++ b/packages/typespec-ts/src/transform/transformParameters.ts @@ -31,6 +31,7 @@ import { import { getOperationGroupName, getOperationName, + getSpecialSerializeInfo, isBinaryPayload } from "../utils/operationUtil.js"; import { @@ -140,7 +141,7 @@ function getParameterMetadata( type === "number[]" || type === "Array" ) { - const serializeInfo = getSpecialSerializeInfo(parameter); + const serializeInfo = getSpecialSerializeInfo(parameter.type, (parameter as any).format); if ( serializeInfo.hasMultiCollection || serializeInfo.hasPipeCollection || @@ -153,11 +154,10 @@ function getParameterMetadata( ", " )} collection, we provide ${serializeInfo.descriptions.join( ", " - )} from serializeHelper.ts to help${ - serializeInfo.hasMultiCollection - ? ", you will probably need to set skipUrlEncoding as true when sending the request" - : "" - }`; + )} from serializeHelper.ts to help${serializeInfo.hasMultiCollection + ? ", you will probably need to set skipUrlEncoding as true when sending the request" + : "" + }`; } } return { @@ -470,53 +470,3 @@ function extractDescriptionsFromBody( ); return description ? [description] : []; } - -export function getSpecialSerializeInfo(parameter: HttpOperationParameter) { - let hasMultiCollection = false; - let hasPipeCollection = false; - let hasSsvCollection = false; - let hasTsvCollection = false; - let hasCsvCollection = false; - const descriptions = []; - const collectionInfo = []; - if ( - (parameter.type === "query" || parameter.type === "header") && - (parameter as any).format === "multi" - ) { - hasMultiCollection = true; - descriptions.push("buildMultiCollection"); - collectionInfo.push("multi"); - } - if (parameter.type === "query" && (parameter as any).format === "ssv") { - hasSsvCollection = true; - descriptions.push("buildSsvCollection"); - collectionInfo.push("ssv"); - } - - if (parameter.type === "query" && (parameter as any).format === "tsv") { - hasTsvCollection = true; - descriptions.push("buildTsvCollection"); - collectionInfo.push("tsv"); - } - - if (parameter.type === "query" && (parameter as any).format === "pipes") { - hasPipeCollection = true; - descriptions.push("buildPipeCollection"); - collectionInfo.push("pipe"); - } - - if (parameter.type === "header" && (parameter as any).format === "csv") { - hasCsvCollection = true; - descriptions.push("buildCsvCollection"); - collectionInfo.push("csv"); - } - return { - hasMultiCollection, - hasPipeCollection, - hasSsvCollection, - hasTsvCollection, - hasCsvCollection, - descriptions, - collectionInfo - }; -} diff --git a/packages/typespec-ts/src/utils/operationUtil.ts b/packages/typespec-ts/src/utils/operationUtil.ts index 1b288f6828..da695eb312 100644 --- a/packages/typespec-ts/src/utils/operationUtil.ts +++ b/packages/typespec-ts/src/utils/operationUtil.ts @@ -350,3 +350,90 @@ export function extractPagedMetadataNested( } return paged; } + +export function getSpecialSerializeInfo( + paramType: string, + paramFormat: string +) { + let hasMultiCollection = getHasMultiCollection(paramType, paramFormat); + let hasPipeCollection = getHasPipeCollection(paramType, paramFormat); + let hasSsvCollection = getHasSsvCollection(paramType, paramFormat); + let hasTsvCollection = getHasTsvCollection(paramType, paramFormat); + let hasCsvCollection = getHasCsvCollection(paramType, paramFormat); + const descriptions = []; + const collectionInfo = []; + if (hasMultiCollection) { + descriptions.push("buildMultiCollection"); + collectionInfo.push("multi"); + } + if (hasSsvCollection) { + descriptions.push("buildSsvCollection"); + collectionInfo.push("ssv"); + } + + if (hasTsvCollection) { + descriptions.push("buildTsvCollection"); + collectionInfo.push("tsv"); + } + + if (hasPipeCollection) { + descriptions.push("buildPipeCollection"); + collectionInfo.push("pipe"); + } + + if (hasCsvCollection) { + descriptions.push("buildCsvCollection"); + collectionInfo.push("csv"); + } + return { + hasMultiCollection, + hasPipeCollection, + hasSsvCollection, + hasTsvCollection, + hasCsvCollection, + descriptions, + collectionInfo + }; +} + +function getHasMultiCollection(paramType: string, paramFormat: string) { + return ( + (paramType === "query" || paramType === "header") && paramFormat === "multi" + ); +} +function getHasSsvCollection(paramType: string, paramFormat: string) { + return paramType === "query" && paramFormat === "ssv"; +} + +function getHasTsvCollection(paramType: string, paramFormat: string) { + return paramType === "query" && paramFormat === "tsv"; +} + +function getHasCsvCollection(paramType: string, paramFormat: string) { + return paramType === "header" && paramFormat === "csv"; +} + +function getHasPipeCollection(paramType: string, paramFormat: string) { + return paramType === "query" && paramFormat === "pipes"; +} + +export function hasCollectionFormatInfo( + paramType: string, + paramFormat: string +) { + return ( + getHasMultiCollection(paramType, paramFormat) || + getHasSsvCollection(paramType, paramFormat) || + getHasTsvCollection(paramType, paramFormat) || + getHasCsvCollection(paramType, paramFormat) || + getHasPipeCollection(paramType, paramFormat) + ); +} + +export function getCollectionFormatFunction( + paramType: string, + paramFormat: string +) { + const detail = getSpecialSerializeInfo(paramType, paramFormat); + return detail.descriptions.length > 0 ? detail.descriptions[0] : undefined; +} 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 e0fbc301d7..b687b2ed80 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 @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { User, CustomPageModel, CustomPage, Page } from "./models/models.js"; +import { User, UserListResults, PagedUser } from "./models/models.js"; import { CreateOrUpdateOptions, CreateOrReplaceOptions, @@ -10,7 +10,7 @@ import { ListWithPageOptions, ListWithCustomPageModelOptions, DeleteOptions, - ExportOptions + ExportOptions, } from "./models/options.js"; import { createBasic, @@ -23,9 +23,8 @@ import { listWithPage, listWithCustomPageModel, deleteOperation, - exportOperation + exportOperation, } from "./api/index.js"; -import { PagedAsyncIterableIterator } from "@azure/core-paging"; export { BasicClientOptions } from "./api/BasicContext.js"; @@ -61,21 +60,21 @@ export class BasicClient { } /** Lists all Users */ - list(options: ListOptions = { requestOptions: {} }): Promise { + list(options: ListOptions = { requestOptions: {} }): Promise { return list(this._client, options); } /** List with Azure.Core.Page<>. */ listWithPage( options: ListWithPageOptions = { requestOptions: {} } - ): PagedAsyncIterableIterator { + ): Promise { return listWithPage(this._client, options); } /** List with custom page model. */ listWithCustomPageModel( options: ListWithCustomPageModelOptions = { requestOptions: {} } - ): Promise { + ): Promise { return listWithCustomPageModel(this._client, options); } 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 8b92c62438..4ad2da2b78 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 @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { User, CustomPageModel, CustomPage, Page } from "../models/models.js"; +import { User, UserListResults, PagedUser } from "../models/models.js"; import { isUnexpected, BasicContext as Client, @@ -23,12 +23,12 @@ import { ListWithCustomPageModelDefaultResponse, ListWithPage200Response, ListWithPageDefaultResponse, - buildMultiCollection } from "../rest/index.js"; import { StreamableMethod, - operationOptionsToRequestParameters + operationOptionsToRequestParameters, } from "@azure-rest/core-client"; +import { buildMultiCollection } from "../rest/index.js"; import { CreateOrUpdateOptions, CreateOrReplaceOptions, @@ -37,18 +37,8 @@ import { ListWithPageOptions, ListWithCustomPageModelOptions, DeleteOptions, - ExportOptions + ExportOptions, } from "../models/options.js"; -import { - PagedAsyncIterableIterator, - PagedResult, - getPagedAsyncIterator -} from "@azure/core-paging"; -import { - getElements, - getNextLink, - getPaginationProperties -} from "../pageHelper.js"; export function _createOrUpdateSend( context: Client, @@ -60,11 +50,14 @@ export function _createOrUpdateSend( | CreateOrUpdate201Response | CreateOrUpdateDefaultResponse > { - return context.path("/azure/core/basic/users/{id}", id).patch({ - ...operationOptionsToRequestParameters(options), - contentType: (options.contentType as any) ?? "application/merge-patch+json", - body: { name: name, orders: options?.orders } - }); + return context + .path("/azure/core/basic/users/{id}", id) + .patch({ + ...operationOptionsToRequestParameters(options), + contentType: + (options.contentType as any) ?? "application/merge-patch+json", + body: { name: name, orders: options?.orders }, + }); } export async function _createOrUpdateDeserialize( @@ -83,9 +76,9 @@ export async function _createOrUpdateDeserialize( orders: (result.body["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"] + detail: p["detail"], })), - etag: result.body["etag"] + etag: result.body["etag"], }; } @@ -110,10 +103,12 @@ export function _createOrReplaceSend( | CreateOrReplace201Response | CreateOrReplaceDefaultResponse > { - return context.path("/azure/core/basic/users/{id}", id).put({ - ...operationOptionsToRequestParameters(options), - body: { name: name, orders: options?.orders } - }); + return context + .path("/azure/core/basic/users/{id}", id) + .put({ + ...operationOptionsToRequestParameters(options), + body: { name: name, orders: options?.orders }, + }); } export async function _createOrReplaceDeserialize( @@ -132,9 +127,9 @@ export async function _createOrReplaceDeserialize( orders: (result.body["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"] + detail: p["detail"], })), - etag: result.body["etag"] + etag: result.body["etag"], }; } @@ -172,9 +167,9 @@ export async function _getDeserialize( orders: (result.body["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"] + detail: p["detail"], })), - etag: result.body["etag"] + etag: result.body["etag"], }; } @@ -192,24 +187,34 @@ export function _listSend( context: Client, options: ListOptions = { requestOptions: {} } ): StreamableMethod { - return context.path("/azure/core/basic/users").get({ - ...operationOptionsToRequestParameters(options), - queryParameters: { - top: options?.top, - skip: options?.skip, - maxpagesize: options?.maxpagesize, - orderby: - options.orderby && buildMultiCollection(options.orderby, "orderBy"), - filter: options?.filter, - select: options.select && buildMultiCollection(options.select, "select"), - expand: options.expand && buildMultiCollection(options.expand, "expand") - } - }); + return context + .path("/azure/core/basic/users") + .get({ + ...operationOptionsToRequestParameters(options), + queryParameters: { + top: options?.top, + skip: options?.skip, + maxpagesize: options?.maxpagesize, + orderby: + options?.orderby !== undefined + ? buildMultiCollection(options?.orderby, "orderby") + : undefined, + filter: options?.filter, + select: + options?.select !== undefined + ? buildMultiCollection(options?.select, "select") + : undefined, + expand: + options?.expand !== undefined + ? buildMultiCollection(options?.expand, "expand") + : undefined, + }, + }); } export async function _listDeserialize( result: List200Response | ListDefaultResponse -): Promise { +): Promise { if (isUnexpected(result)) { throw result.body; } @@ -221,11 +226,11 @@ export async function _listDeserialize( orders: (p["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"] + detail: p["detail"], })), - etag: p["etag"] + etag: p["etag"], })), - nextLink: result.body["nextLink"] + nextLink: result.body["nextLink"], }; } @@ -233,7 +238,7 @@ export async function _listDeserialize( export async function list( context: Client, options: ListOptions = { requestOptions: {} } -): Promise { +): Promise { const result = await _listSend(context, options); return _listDeserialize(result); } @@ -249,7 +254,7 @@ export function _listWithPageSend( export async function _listWithPageDeserialize( result: ListWithPage200Response | ListWithPageDefaultResponse -): Promise { +): Promise { if (isUnexpected(result)) { throw result.body; } @@ -261,48 +266,21 @@ export async function _listWithPageDeserialize( orders: (p["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"] + detail: p["detail"], })), - etag: p["etag"] + etag: p["etag"], })), - nextLink: result.body["nextLink"] + nextLink: result.body["nextLink"], }; } /** List with Azure.Core.Page<>. */ -export function listWithPage( +export async function listWithPage( context: Client, options: ListWithPageOptions = { requestOptions: {} } -): PagedAsyncIterableIterator { - return listWithPageGenerator(context, options); -} - -function listWithPageGenerator( - context: Client, - options: ListWithPageOptions -): PagedAsyncIterableIterator { - let firstRun = true; - const pagedResult: PagedResult = { - firstPageLink: "", - getPage: async (pageLink: string) => { - const result = firstRun - ? await _listWithPageSend(context, options) - : await context.pathUnchecked(pageLink).get(); - const { itemName, nextLinkName } = getPaginationProperties(result); - firstRun = false; - const nextLink = getNextLink(result.body, nextLinkName); - const values = getElements( - await _listWithPageDeserialize(result), - itemName - ); - return { - page: values, - nextPageLink: nextLink - }; - } - }; - - return getPagedAsyncIterator(pagedResult); +): Promise { + const result = await _listWithPageSend(context, options); + return _listWithPageDeserialize(result); } export function _listWithCustomPageModelSend( @@ -320,7 +298,7 @@ export async function _listWithCustomPageModelDeserialize( result: | ListWithCustomPageModel200Response | ListWithCustomPageModelDefaultResponse -): Promise { +): Promise { if (isUnexpected(result)) { throw result.body; } @@ -332,11 +310,11 @@ export async function _listWithCustomPageModelDeserialize( orders: (p["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"] + detail: p["detail"], })), - etag: p["etag"] + etag: p["etag"], })), - nextLink: result.body["nextLink"] + nextLink: result.body["nextLink"], }; } @@ -344,7 +322,7 @@ export async function _listWithCustomPageModelDeserialize( export async function listWithCustomPageModel( context: Client, options: ListWithCustomPageModelOptions = { requestOptions: {} } -): Promise { +): Promise { const result = await _listWithCustomPageModelSend(context, options); return _listWithCustomPageModelDeserialize(result); } @@ -393,10 +371,12 @@ export function _exportOperationSend( ): StreamableMethod< ExportOperation200Response | ExportOperationDefaultResponse > { - return context.path("/azure/core/basic/users/{id}:export", id).post({ - ...operationOptionsToRequestParameters(options), - queryParameters: { format: format } - }); + return context + .path("/azure/core/basic/users/{id}:export", id) + .post({ + ...operationOptionsToRequestParameters(options), + queryParameters: { format: format }, + }); } export async function _exportOperationDeserialize( @@ -412,9 +392,9 @@ export async function _exportOperationDeserialize( orders: (result.body["orders"] ?? []).map((p) => ({ id: p["id"], userId: p["userId"], - detail: p["detail"] + detail: p["detail"], })), - etag: result.body["etag"] + etag: result.body["etag"], }; } diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts index e6a6381fb3..6521a8e214 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/index.ts @@ -5,9 +5,8 @@ export { BasicClient, BasicClientOptions } from "./BasicClient.js"; export { User, UserOrder, - CustomPageModel, - CustomPage, - Page, + UserListResults, + PagedUser, CreateOrUpdateOptions, CreateOrReplaceOptions, GetOptions, diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts index 4dd7d24afb..afed0676fd 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/index.ts @@ -1,13 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -export { - User, - UserOrder, - CustomPageModel, - CustomPage, - Page, -} from "./models.js"; +export { User, UserOrder, UserListResults, PagedUser } from "./models.js"; export { CreateOrUpdateOptions, CreateOrReplaceOptions, diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/models.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/models.ts index 2554e6564e..8257cd9928 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/models.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/models/models.ts @@ -23,7 +23,7 @@ export interface UserOrder { detail: string; } -export interface CustomPageModel { +export interface UserListResults { /** List of items. */ items: User[]; /** Link to fetch more items. */ @@ -31,7 +31,7 @@ export interface CustomPageModel { } /** Paged collection of User items */ -export interface CustomPage { +export interface PagedUser { /** The User items on this page */ value: User[]; /** The link to the next page of items */ @@ -39,7 +39,7 @@ export interface CustomPage { } /** Paged collection of User items */ -export interface Page { +export interface PagedUser { /** The User items on this page */ value: User[]; /** The link to the next page of items */ diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/pageHelper.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/pageHelper.ts deleted file mode 100644 index ecc65ce4cc..0000000000 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/pageHelper.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { PathUncheckedResponse } from "@azure-rest/core-client"; - -/** - * Gets for the value of nextLink in the body - */ -export function getNextLink( - body: unknown, - nextLinkName?: string -): string | undefined { - if (!nextLinkName) { - return undefined; - } - - const nextLink = (body as Record)[nextLinkName]; - - if (typeof nextLink !== "string" && typeof nextLink !== "undefined") { - throw new Error( - `Body Property ${nextLinkName} should be a string or undefined` - ); - } - - return nextLink; -} - -/** - * Gets the elements of the current request in the body. - */ -export function getElements(body: unknown, itemName: string): T[] { - const value = (body as Record)[itemName] as T[]; - - // value has to be an array according to the x-ms-pageable extension. - // The fact that this must be an array is used above to calculate the - // type of elements in the page in PaginateReturn - if (!Array.isArray(value)) { - throw new Error( - `Couldn't paginate response\n Body doesn't contain an array property with name: ${itemName}` - ); - } - - return value ?? []; -} - -export function getPaginationProperties( - initialResponse: PathUncheckedResponse -) { - // Build a set with the passed custom nextLinkNames - const nextLinkNames = new Set(["nextLink"]); - - // Build a set with the passed custom set of itemNames - const itemNames = new Set(["value", "items"]); - - let nextLinkName: string | undefined; - let itemName: string | undefined; - - for (const name of nextLinkNames) { - const nextLink = (initialResponse.body as Record)[ - name - ] as string; - if (nextLink) { - nextLinkName = name; - break; - } - } - - for (const name of itemNames) { - const item = (initialResponse.body as Record)[ - name - ] as string; - if (item) { - itemName = name; - break; - } - } - - if (!itemName) { - throw new Error( - `Couldn't paginate response\n Body doesn't contain an array property with name: ${[ - ...itemNames - ].join(" OR ")}` - ); - } - - return { itemName, nextLinkName }; -} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/outputModels.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/outputModels.ts index fdba810e47..6a2772872a 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/outputModels.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/outputModels.ts @@ -32,7 +32,5 @@ export interface UserListResultsOutput { nextLink?: string; } -/** Paged collection of User items */ -export type UserListOutput = Paged; /** Paged collection of User items */ export type PagedUserOutput = Paged; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts index ddd916eda0..77eadda863 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core/src/rest/responses.ts @@ -5,7 +5,6 @@ import { RawHttpHeaders } from "@azure/core-rest-pipeline"; import { HttpResponse, ErrorResponse } from "@azure-rest/core-client"; import { UserOutput, - UserListOutput, PagedUserOutput, UserListResultsOutput, } from "./outputModels.js"; @@ -76,7 +75,7 @@ export interface GetDefaultResponse extends HttpResponse { /** The request has succeeded. */ export interface List200Response extends HttpResponse { status: "200"; - body: UserListOutput; + body: PagedUserOutput; } export interface ListDefaultHeaders { From b5f48a31c919c671e78529fa18ec6bda79d01736 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Sun, 20 Aug 2023 18:20:26 +0800 Subject: [PATCH 06/16] Enable collection format and resolve name operation conflict --- .../src/modular/buildClassicalClient.ts | 22 ++- .../typespec-ts/src/modular/buildCodeModel.ts | 29 +++ .../src/modular/helpers/operationHelpers.ts | 42 ++--- .../src/modular/modularCodeModel.ts | 1 + .../typespec-ts/src/utils/operationUtil.ts | 2 +- .../test/commands/cadl-ranch-list.ts | 6 +- .../test/modularIntegration/azureCore.spec.ts | 16 +- .../collectionFormat.spec.ts | 66 +++++++ .../azure/core/src/api/operations.ts | 2 +- .../src/CollectionFormatClient.ts | 57 ++++++ .../src/api/CollectionFormatContext.ts | 19 ++ .../collection-format/src/api/header.ts | 42 +++++ .../collection-format/src/api/index.ts | 16 ++ .../collection-format/src/api/query.ts | 167 ++++++++++++++++++ .../parameters/collection-format/src/index.ts | 15 ++ .../collection-format/src/logger.ts | 5 + .../collection-format/src/models/index.ts | 12 ++ .../collection-format/src/models/models.ts | 2 + .../collection-format/src/models/options.ts | 16 ++ .../src/rest/clientDefinitions.ts | 63 +++++++ .../src/rest/collectionFormatClient.ts | 35 ++++ .../collection-format/src/rest/index.ts | 12 ++ .../collection-format/src/rest/parameters.ts | 71 ++++++++ .../collection-format/src/rest/responses.ts | 34 ++++ .../src/rest/serializeHelper.ts | 29 +++ .../collection-format/tspconfig.yaml | 15 ++ 26 files changed, 751 insertions(+), 45 deletions(-) create mode 100644 packages/typespec-ts/test/modularIntegration/collectionFormat.spec.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/CollectionFormatClient.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/CollectionFormatContext.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/header.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/query.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/logger.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/models.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/options.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/clientDefinitions.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/collectionFormatClient.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/parameters.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/responses.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/serializeHelper.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/tspconfig.yaml diff --git a/packages/typespec-ts/src/modular/buildClassicalClient.ts b/packages/typespec-ts/src/modular/buildClassicalClient.ts index 0ac0c9aa2f..adf28655b5 100644 --- a/packages/typespec-ts/src/modular/buildClassicalClient.ts +++ b/packages/typespec-ts/src/modular/buildClassicalClient.ts @@ -151,6 +151,10 @@ function buildClientOperationGroups( clientClass: ClassDeclaration, subfolder: string ) { + const operationMap = new Map< + OptionalKind, + string | undefined + >(); for (const operationGroup of client.operationGroups) { const operationGroupName = toCamelCase(operationGroup.propertyName); let clientType = "Client"; @@ -158,9 +162,11 @@ function buildClientOperationGroups( clientType = `Client.${clientClass.getName()}`; } const operationDeclarations: OptionalKind[] = - operationGroup.operations.map((operation) => - getOperationFunction(operation, clientType) - ); + operationGroup.operations.map((operation) => { + const declarations = getOperationFunction(operation, clientType); + operationMap.set(declarations, operation.oriName); + return declarations; + }); if (operationGroupName && operationGroupName !== "") { clientClass.addProperty({ @@ -168,7 +174,7 @@ function buildClientOperationGroups( initializer: ` { ${operationDeclarations.map((d) => { - return `${d.name}: (${d.parameters + return `${getClassicalName(d)}: (${d.parameters ?.filter((p) => p.name !== "context") .map( (p) => p.name + (p.name === "options" ? "?" : "") + ": " + p.type @@ -186,7 +192,7 @@ function buildClientOperationGroups( operationDeclarations.map((d) => { const method: MethodDeclarationStructure = { docs: d.docs, - name: d.name ?? "FIXME", + name: getClassicalName(d), kind: StructureKind.Method, returnType: d.returnType, parameters: d.parameters?.filter((p) => p.name !== "context"), @@ -203,4 +209,10 @@ function buildClientOperationGroups( ); } } + + function getClassicalName( + declaration: OptionalKind + ) { + return operationMap.get(declaration) ?? declaration.name ?? "FIXME"; + } } diff --git a/packages/typespec-ts/src/modular/buildCodeModel.ts b/packages/typespec-ts/src/modular/buildCodeModel.ts index 80797c0fc1..7ef7dd6134 100644 --- a/packages/typespec-ts/src/modular/buildCodeModel.ts +++ b/packages/typespec-ts/src/modular/buildCodeModel.ts @@ -1319,9 +1319,38 @@ function emitOperationGroups( operations: clientOperations }); } + resolveConflictIfExist(operationGroups); return operationGroups; } +function resolveConflictIfExist(operationGroups: OperationGroup[]) { + if (operationGroups.length < 2) { + return; + } + + const nameSet = new Set(); + const hasConflict = operationGroups.some((g) => + g.operations.some((op) => { + if (nameSet.has(op.name)) { + return true; + } else { + nameSet.add(op.name); + return false; + } + }) + ); + if (!hasConflict) { + return; + } + // Append operation group prefix + operationGroups.forEach((g) => + g.operations.forEach((op) => { + op.oriName = op.name; + op.name = `${g.propertyName}_${op.name}`; + }) + ); +} + function getServerHelper( program: Program, namespace: Namespace diff --git a/packages/typespec-ts/src/modular/helpers/operationHelpers.ts b/packages/typespec-ts/src/modular/helpers/operationHelpers.ts index cedacf8f2b..2864d6ab29 100644 --- a/packages/typespec-ts/src/modular/helpers/operationHelpers.ts +++ b/packages/typespec-ts/src/modular/helpers/operationHelpers.ts @@ -26,7 +26,7 @@ import { getDocsFromDescription } from "./docsHelpers.js"; import { - getCollectionFormatFunction, + getCollectionFormatHelper, hasCollectionFormatInfo } from "../../utils/operationUtil.js"; @@ -264,10 +264,12 @@ export function getOperationFunction( }; } -export function getOperationOptionsName(operation: Operation) { - const optionName = `${toPascalCase(operation.groupName)}${toPascalCase( - operation.name - )}Options`; +export function getOperationOptionsName( + operation: Operation, + includeGroupName = false +) { + const prefix = includeGroupName ? toPascalCase(operation.groupName) : ""; + const optionName = `${prefix}${toPascalCase(operation.name)}Options`; if (operation.bodyParameter?.type.name === optionName) { return optionName.replace(/Options$/, "RequestOptions"); } @@ -317,9 +319,9 @@ function getRequestParameters( } if (parametersImplementation.header.length) { - paramStr = `${paramStr}\nheaders: {${ - parametersImplementation.header.join(",\n") + "," - },`; + paramStr = `${paramStr}\nheaders: {${parametersImplementation.header.join( + ",\n" + )}},`; } if (parametersImplementation.query.length) { @@ -400,8 +402,7 @@ function getParameterMap( } if (hasCollectionFormatInfo((param as any).location, (param as any).format)) { - console.log(">>>>>>>>>>>>>>>>>hasCollectionFormatInfo", param); - return getCollectionFormatParamMap(param as Parameter, importSet); + return getCollectionFormat(param as Parameter); } // if the parameter or property is optional, we don't need to handle the default value @@ -416,27 +417,20 @@ function getParameterMap( throw new Error(`Parameter ${param.clientName} is not supported`); } -function getCollectionFormatParamMap( - param: Parameter, - importSet: Map> -) { - const rlcUtilSet = importSet.get("../rest/index.js"); - const collectionInfo = getCollectionFormatFunction( +function getCollectionFormat(param: Parameter) { + const collectionInfo = getCollectionFormatHelper( param.location, param.format ?? "" ); - console.log(">>>>>>>>>>>>>>>>>getCollectionFormatParamMap", collectionInfo); if (!collectionInfo) { throw "Has collection format info but without helper function detected"; } - const isOptional = param.optional ? "options?." : ""; - const clientName = `${isOptional}${param.clientName}`; - if (!rlcUtilSet) { - importSet.set("../rest/index.js", new Set().add(collectionInfo)); - } else { - rlcUtilSet.add(collectionInfo); + const isMulti = (param.format ?? "").toLowerCase() === "multi"; + const additionalParam = isMulti ? `, "${param.restApiName}"` : ""; + if (!param.optional) { + return `"${param.restApiName}": ${collectionInfo}(${param.clientName}${additionalParam})`; } - return `"${param.restApiName}": ${clientName} !== undefined ? ${collectionInfo}(${clientName}, "${param.restApiName}"): undefined`; + return `"${param.restApiName}": options?.${param.clientName} !== undefined ? ${collectionInfo}(options?.${param.clientName}${additionalParam}): undefined`; } function isContentType(param: Parameter): boolean { diff --git a/packages/typespec-ts/src/modular/modularCodeModel.ts b/packages/typespec-ts/src/modular/modularCodeModel.ts index a81d69724d..004b701d19 100644 --- a/packages/typespec-ts/src/modular/modularCodeModel.ts +++ b/packages/typespec-ts/src/modular/modularCodeModel.ts @@ -137,6 +137,7 @@ export interface Response { export interface Operation { name: string; + oriName?: string; description: string; summary: string; url: string; diff --git a/packages/typespec-ts/src/utils/operationUtil.ts b/packages/typespec-ts/src/utils/operationUtil.ts index da695eb312..23184e3b6e 100644 --- a/packages/typespec-ts/src/utils/operationUtil.ts +++ b/packages/typespec-ts/src/utils/operationUtil.ts @@ -430,7 +430,7 @@ export function hasCollectionFormatInfo( ); } -export function getCollectionFormatFunction( +export function getCollectionFormatHelper( paramType: string, paramFormat: string ) { diff --git a/packages/typespec-ts/test/commands/cadl-ranch-list.ts b/packages/typespec-ts/test/commands/cadl-ranch-list.ts index faa6c59305..0f46a35f47 100644 --- a/packages/typespec-ts/test/commands/cadl-ranch-list.ts +++ b/packages/typespec-ts/test/commands/cadl-ranch-list.ts @@ -198,7 +198,11 @@ export const modularTsps: TypeSpecRanchConfig[] = [ }, { outputPath: "azure/core", - inputPath: "azure/core/basic", + inputPath: "azure/core/basic" + }, + { + outputPath: "parameters/collection-format", + inputPath: "parameters/collection-format", debug: true } ]; diff --git a/packages/typespec-ts/test/modularIntegration/azureCore.spec.ts b/packages/typespec-ts/test/modularIntegration/azureCore.spec.ts index 79e8657211..631e5f0fe7 100644 --- a/packages/typespec-ts/test/modularIntegration/azureCore.spec.ts +++ b/packages/typespec-ts/test/modularIntegration/azureCore.spec.ts @@ -1,7 +1,7 @@ import { BasicClient } from "./generated/azure/core/src/index.js"; import { assert } from "chai"; -describe.only("BasicClient Classical Client", () => { +describe("BasicClient Classical Client", () => { let client: BasicClient; beforeEach(() => { @@ -10,17 +10,7 @@ describe.only("BasicClient Classical Client", () => { }); }); - it("should list items with paging", async () => { - try { - const iter = client.listWithPage(); - const resArray = new Array(); - for await (let item of iter) { - resArray.push(item); - } - assert.strictEqual(resArray.length, 1); - } catch (err) { - console.log(err); - assert.fail(err as string); - } + it("should create the client", async () => { + assert.isNotNull(client); }); }); diff --git a/packages/typespec-ts/test/modularIntegration/collectionFormat.spec.ts b/packages/typespec-ts/test/modularIntegration/collectionFormat.spec.ts new file mode 100644 index 0000000000..09aa024f3f --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/collectionFormat.spec.ts @@ -0,0 +1,66 @@ +import { CollectionFormatClient } from "./generated/parameters/collection-format/src/index.js"; +import { assert } from "chai"; + +describe("CollectionFormatClient Classical Client", () => { + let client: CollectionFormatClient; + + beforeEach(() => { + client = new CollectionFormatClient({ + allowInsecureConnection: true + }); + }); + + it("should send csv format in query", async () => { + try { + const result = await client.query.csv(["blue", "red", "green"]); + assert.strictEqual(result, undefined); + } catch (err) { + assert.fail(err as string); + } + }); + + it("should send multi format in query", async () => { + try { + const result = await client.query.multi(["blue", "red", "green"]); + assert.strictEqual(result, undefined); + } catch (err) { + assert.fail(err as string); + } + }); + + it("should send pipes format in query", async () => { + try { + const result = await client.query.pipes(["blue", "red", "green"]); + assert.strictEqual(result, undefined); + } catch (err) { + assert.fail(err as string); + } + }); + + it("should send ssv format in query", async () => { + try { + const result = await client.query.ssv(["blue", "red", "green"]); + assert.strictEqual(result, undefined); + } catch (err) { + assert.fail(err as string); + } + }); + + it("should send tsv format in query", async () => { + try { + const result = await client.query.tsv(["blue", "red", "green"]); + assert.strictEqual(result, undefined); + } catch (err) { + assert.fail(err as string); + } + }); + + it("should send csv format in header", async () => { + try { + const result = await client.header.csv(["blue", "red", "green"]); + assert.strictEqual(result, undefined); + } catch (err) { + assert.fail(err as string); + } + }); +}); 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 4ad2da2b78..492cd4f9a9 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 @@ -5,6 +5,7 @@ import { User, UserListResults, PagedUser } from "../models/models.js"; import { isUnexpected, BasicContext as Client, + buildMultiCollection, CreateOrReplace200Response, CreateOrReplace201Response, CreateOrReplaceDefaultResponse, @@ -28,7 +29,6 @@ import { StreamableMethod, operationOptionsToRequestParameters, } from "@azure-rest/core-client"; -import { buildMultiCollection } from "../rest/index.js"; import { CreateOrUpdateOptions, CreateOrReplaceOptions, diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/CollectionFormatClient.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/CollectionFormatClient.ts new file mode 100644 index 0000000000..7dbc343a55 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/CollectionFormatClient.ts @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import "./models/models.js"; +import { + QueryMultiOptions, + QuerySsvOptions, + QueryTsvOptions, + QueryPipesOptions, + QueryCsvOptions, + HeaderCsvOptions, +} from "./models/options.js"; +import { + createCollectionFormat, + CollectionFormatClientOptions, + CollectionFormatContext, + headerCsv, + queryMulti, + querySsv, + queryTsv, + queryPipes, + queryCsv, +} from "./api/index.js"; + +export { CollectionFormatClientOptions } from "./api/CollectionFormatContext.js"; + +export class CollectionFormatClient { + private _client: CollectionFormatContext; + + /** Test for collectionFormat. */ + constructor(options: CollectionFormatClientOptions = {}) { + this._client = createCollectionFormat(options); + } + + query = { + multi: (colors: string[], options?: QueryMultiOptions): Promise => { + return queryMulti(this._client, colors, options); + }, + ssv: (colors: string[], options?: QuerySsvOptions): Promise => { + return querySsv(this._client, colors, options); + }, + tsv: (colors: string[], options?: QueryTsvOptions): Promise => { + return queryTsv(this._client, colors, options); + }, + pipes: (colors: string[], options?: QueryPipesOptions): Promise => { + return queryPipes(this._client, colors, options); + }, + csv: (colors: string[], options?: QueryCsvOptions): Promise => { + return queryCsv(this._client, colors, options); + }, + }; + header = { + csv: (colors: string[], options?: HeaderCsvOptions): Promise => { + return headerCsv(this._client, colors, options); + }, + }; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/CollectionFormatContext.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/CollectionFormatContext.ts new file mode 100644 index 0000000000..43356d2199 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/CollectionFormatContext.ts @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import "../models/models.js"; +import { ClientOptions } from "@azure-rest/core-client"; +import { CollectionFormatContext } from "../rest/index.js"; +import getClient from "../rest/index.js"; + +export interface CollectionFormatClientOptions extends ClientOptions {} + +export { CollectionFormatContext } from "../rest/index.js"; + +/** Test for collectionFormat. */ +export function createCollectionFormat( + options: CollectionFormatClientOptions = {} +): CollectionFormatContext { + const clientContext = getClient(options); + return clientContext; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/header.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/header.ts new file mode 100644 index 0000000000..e419ae4632 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/header.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import "../models/models.js"; +import { + buildCsvCollection, + CollectionFormatContext as Client, + HeaderCsv204Response, +} from "../rest/index.js"; +import { + StreamableMethod, + operationOptionsToRequestParameters, +} from "@azure-rest/core-client"; +import { HeaderCsvOptions } from "../models/options.js"; + +export function _headerCsvSend( + context: Client, + colors: string[], + options: HeaderCsvOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/collection-format/header/csv") + .get({ + ...operationOptionsToRequestParameters(options), + headers: { colors: buildCsvCollection(colors) }, + }); +} + +export async function _headerCsvDeserialize( + _result: HeaderCsv204Response +): Promise { + return; +} + +export async function headerCsv( + context: Client, + colors: string[], + options: HeaderCsvOptions = { requestOptions: {} } +): Promise { + const result = await _headerCsvSend(context, colors, options); + return _headerCsvDeserialize(result); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/index.ts new file mode 100644 index 0000000000..b29a292c01 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/index.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { + createCollectionFormat, + CollectionFormatClientOptions, + CollectionFormatContext, +} from "./CollectionFormatContext.js"; +export { headerCsv } from "./header.js"; +export { + queryMulti, + querySsv, + queryTsv, + queryPipes, + queryCsv, +} from "./query.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/query.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/query.ts new file mode 100644 index 0000000000..d6d3306868 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/query.ts @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import "../models/models.js"; +import { + buildMultiCollection, + buildPipeCollection, + buildSsvCollection, + buildTsvCollection, + CollectionFormatContext as Client, + QueryCsv204Response, + QueryMulti204Response, + QueryPipes204Response, + QuerySsv204Response, + QueryTsv204Response, +} from "../rest/index.js"; +import { + StreamableMethod, + operationOptionsToRequestParameters, +} from "@azure-rest/core-client"; +import { + QueryMultiOptions, + QuerySsvOptions, + QueryTsvOptions, + QueryPipesOptions, + QueryCsvOptions, +} from "../models/options.js"; + +export function _queryMultiSend( + context: Client, + colors: string[], + options: QueryMultiOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/collection-format/query/multi") + .get({ + ...operationOptionsToRequestParameters(options), + queryParameters: { colors: buildMultiCollection(colors, "colors") }, + }); +} + +export async function _queryMultiDeserialize( + _result: QueryMulti204Response +): Promise { + return; +} + +export async function queryMulti( + context: Client, + colors: string[], + options: QueryMultiOptions = { requestOptions: {} } +): Promise { + const result = await _queryMultiSend(context, colors, options); + return _queryMultiDeserialize(result); +} + +export function _querySsvSend( + context: Client, + colors: string[], + options: QuerySsvOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/collection-format/query/ssv") + .get({ + ...operationOptionsToRequestParameters(options), + queryParameters: { colors: buildSsvCollection(colors) }, + }); +} + +export async function _querySsvDeserialize( + _result: QuerySsv204Response +): Promise { + return; +} + +export async function querySsv( + context: Client, + colors: string[], + options: QuerySsvOptions = { requestOptions: {} } +): Promise { + const result = await _querySsvSend(context, colors, options); + return _querySsvDeserialize(result); +} + +export function _queryTsvSend( + context: Client, + colors: string[], + options: QueryTsvOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/collection-format/query/tsv") + .get({ + ...operationOptionsToRequestParameters(options), + queryParameters: { colors: buildTsvCollection(colors) }, + }); +} + +export async function _queryTsvDeserialize( + _result: QueryTsv204Response +): Promise { + return; +} + +export async function queryTsv( + context: Client, + colors: string[], + options: QueryTsvOptions = { requestOptions: {} } +): Promise { + const result = await _queryTsvSend(context, colors, options); + return _queryTsvDeserialize(result); +} + +export function _queryPipesSend( + context: Client, + colors: string[], + options: QueryPipesOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/collection-format/query/pipes") + .get({ + ...operationOptionsToRequestParameters(options), + queryParameters: { colors: buildPipeCollection(colors) }, + }); +} + +export async function _queryPipesDeserialize( + _result: QueryPipes204Response +): Promise { + return; +} + +export async function queryPipes( + context: Client, + colors: string[], + options: QueryPipesOptions = { requestOptions: {} } +): Promise { + const result = await _queryPipesSend(context, colors, options); + return _queryPipesDeserialize(result); +} + +export function _queryCsvSend( + context: Client, + colors: string[], + options: QueryCsvOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/parameters/collection-format/query/csv") + .get({ + ...operationOptionsToRequestParameters(options), + queryParameters: { colors: colors }, + }); +} + +export async function _queryCsvDeserialize( + _result: QueryCsv204Response +): Promise { + return; +} + +export async function queryCsv( + context: Client, + colors: string[], + options: QueryCsvOptions = { requestOptions: {} } +): Promise { + const result = await _queryCsvSend(context, colors, options); + return _queryCsvDeserialize(result); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/index.ts new file mode 100644 index 0000000000..e3df41ce12 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/index.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { + CollectionFormatClient, + CollectionFormatClientOptions, +} from "./CollectionFormatClient.js"; +export { + QueryMultiOptions, + QuerySsvOptions, + QueryTsvOptions, + QueryPipesOptions, + QueryCsvOptions, + HeaderCsvOptions, +} from "./models/index.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/logger.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/logger.ts new file mode 100644 index 0000000000..afa53b1844 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/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("azure-collection-format"); diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/index.ts new file mode 100644 index 0000000000..2565f14b07 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/index.ts @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export * from "./models.js"; +export { + QueryMultiOptions, + QuerySsvOptions, + QueryTsvOptions, + QueryPipesOptions, + QueryCsvOptions, + HeaderCsvOptions, +} from "./options.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/models.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/models.ts new file mode 100644 index 0000000000..fd2aca680c --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/models.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/options.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/options.ts new file mode 100644 index 0000000000..35eafdd2c4 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/options.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { OperationOptions } from "@azure-rest/core-client"; + +export interface QueryMultiOptions extends OperationOptions {} + +export interface QuerySsvOptions extends OperationOptions {} + +export interface QueryTsvOptions extends OperationOptions {} + +export interface QueryPipesOptions extends OperationOptions {} + +export interface QueryCsvOptions extends OperationOptions {} + +export interface HeaderCsvOptions extends OperationOptions {} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/clientDefinitions.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/clientDefinitions.ts new file mode 100644 index 0000000000..813ddb63d9 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/clientDefinitions.ts @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + QueryMultiParameters, + QuerySsvParameters, + QueryTsvParameters, + QueryPipesParameters, + QueryCsvParameters, + HeaderCsvParameters, +} from "./parameters.js"; +import { + QueryMulti204Response, + QuerySsv204Response, + QueryTsv204Response, + QueryPipes204Response, + QueryCsv204Response, + HeaderCsv204Response, +} from "./responses.js"; +import { Client, StreamableMethod } from "@azure-rest/core-client"; + +export interface QueryMulti { + get(options: QueryMultiParameters): StreamableMethod; +} + +export interface QuerySsv { + get(options: QuerySsvParameters): StreamableMethod; +} + +export interface QueryTsv { + get(options: QueryTsvParameters): StreamableMethod; +} + +export interface QueryPipes { + get(options: QueryPipesParameters): StreamableMethod; +} + +export interface QueryCsv { + get(options: QueryCsvParameters): StreamableMethod; +} + +export interface HeaderCsv { + get(options: HeaderCsvParameters): StreamableMethod; +} + +export interface Routes { + /** Resource for '/parameters/collection-format/query/multi' has methods for the following verbs: get */ + (path: "/parameters/collection-format/query/multi"): QueryMulti; + /** Resource for '/parameters/collection-format/query/ssv' has methods for the following verbs: get */ + (path: "/parameters/collection-format/query/ssv"): QuerySsv; + /** Resource for '/parameters/collection-format/query/tsv' has methods for the following verbs: get */ + (path: "/parameters/collection-format/query/tsv"): QueryTsv; + /** Resource for '/parameters/collection-format/query/pipes' has methods for the following verbs: get */ + (path: "/parameters/collection-format/query/pipes"): QueryPipes; + /** Resource for '/parameters/collection-format/query/csv' has methods for the following verbs: get */ + (path: "/parameters/collection-format/query/csv"): QueryCsv; + /** Resource for '/parameters/collection-format/header/csv' has methods for the following verbs: get */ + (path: "/parameters/collection-format/header/csv"): HeaderCsv; +} + +export type CollectionFormatContext = Client & { + path: Routes; +}; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/collectionFormatClient.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/collectionFormatClient.ts new file mode 100644 index 0000000000..b83bbac08f --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/collectionFormatClient.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 { CollectionFormatContext } from "./clientDefinitions.js"; + +/** + * Initialize a new instance of `CollectionFormatContext` + * @param options - the parameter for all optional parameters + */ +export default function createClient( + options: ClientOptions = {} +): CollectionFormatContext { + const baseUrl = options.baseUrl ?? `http://localhost:3000`; + options.apiVersion = options.apiVersion ?? "1.0.0"; + const userAgentInfo = `azsdk-js-azure-collection-format-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 CollectionFormatContext; + + return client; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/index.ts new file mode 100644 index 0000000000..3b884ba622 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/index.ts @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import CollectionFormatClient from "./collectionFormatClient.js"; + +export * from "./collectionFormatClient.js"; +export * from "./parameters.js"; +export * from "./responses.js"; +export * from "./clientDefinitions.js"; +export * from "./serializeHelper.js"; + +export default CollectionFormatClient; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/parameters.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/parameters.ts new file mode 100644 index 0000000000..7ecdd5ff96 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/parameters.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { RawHttpHeadersInput } from "@azure/core-rest-pipeline"; +import { RequestParameters } from "@azure-rest/core-client"; + +export interface QueryMultiQueryParamProperties { + /** Possible values for colors are [blue,red,green] This parameter needs to be formatted as multi collection, we provide buildMultiCollection from serializeHelper.ts to help, you will probably need to set skipUrlEncoding as true when sending the request */ + colors: string; +} + +export interface QueryMultiQueryParam { + queryParameters: QueryMultiQueryParamProperties; +} + +export type QueryMultiParameters = QueryMultiQueryParam & RequestParameters; + +export interface QuerySsvQueryParamProperties { + /** Possible values for colors are [blue,red,green] This parameter needs to be formatted as ssv collection, we provide buildSsvCollection from serializeHelper.ts to help */ + colors: string; +} + +export interface QuerySsvQueryParam { + queryParameters: QuerySsvQueryParamProperties; +} + +export type QuerySsvParameters = QuerySsvQueryParam & RequestParameters; + +export interface QueryTsvQueryParamProperties { + /** Possible values for colors are [blue,red,green] This parameter needs to be formatted as tsv collection, we provide buildTsvCollection from serializeHelper.ts to help */ + colors: string; +} + +export interface QueryTsvQueryParam { + queryParameters: QueryTsvQueryParamProperties; +} + +export type QueryTsvParameters = QueryTsvQueryParam & RequestParameters; + +export interface QueryPipesQueryParamProperties { + /** Possible values for colors are [blue,red,green] This parameter needs to be formatted as pipe collection, we provide buildPipeCollection from serializeHelper.ts to help */ + colors: string; +} + +export interface QueryPipesQueryParam { + queryParameters: QueryPipesQueryParamProperties; +} + +export type QueryPipesParameters = QueryPipesQueryParam & RequestParameters; + +export interface QueryCsvQueryParamProperties { + /** Possible values for colors are [blue,red,green] */ + colors: string[]; +} + +export interface QueryCsvQueryParam { + queryParameters: QueryCsvQueryParamProperties; +} + +export type QueryCsvParameters = QueryCsvQueryParam & RequestParameters; + +export interface HeaderCsvHeaders { + /** Possible values for colors are [blue,red,green] This parameter needs to be formatted as csv collection, we provide buildCsvCollection from serializeHelper.ts to help */ + colors: string; +} + +export interface HeaderCsvHeaderParam { + headers: RawHttpHeadersInput & HeaderCsvHeaders; +} + +export type HeaderCsvParameters = HeaderCsvHeaderParam & RequestParameters; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/responses.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/responses.ts new file mode 100644 index 0000000000..3ae77049a4 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/responses.ts @@ -0,0 +1,34 @@ +// 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 QueryMulti204Response extends HttpResponse { + status: "204"; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface QuerySsv204Response extends HttpResponse { + status: "204"; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface QueryTsv204Response extends HttpResponse { + status: "204"; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface QueryPipes204Response extends HttpResponse { + status: "204"; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface QueryCsv204Response extends HttpResponse { + status: "204"; +} + +/** There is no content to send for this request, but the headers may be useful. */ +export interface HeaderCsv204Response extends HttpResponse { + status: "204"; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/serializeHelper.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/serializeHelper.ts new file mode 100644 index 0000000000..255cd5f812 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/rest/serializeHelper.ts @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export function buildMultiCollection(items: string[], parameterName: string) { + return items + .map((item, index) => { + if (index === 0) { + return item; + } + return `${parameterName}=${item}`; + }) + .join("&"); +} + +export function buildPipeCollection(items: string[] | number[]): string { + return items.join("|"); +} + +export function buildSsvCollection(items: string[] | number[]): string { + return items.join(" "); +} + +export function buildTsvCollection(items: string[] | number[]) { + return items.join("\t"); +} + +export function buildCsvCollection(items: string[] | number[]) { + return items.join(","); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/tspconfig.yaml b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/tspconfig.yaml new file mode 100644 index 0000000000..3303e165fb --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/tspconfig.yaml @@ -0,0 +1,15 @@ +emit: + - "@azure-tools/typespec-ts" +options: + "@azure-tools/typespec-ts": + "emitter-output-dir": "{project-root}" + generateMetadata: false + generateTest: false + addCredentials: false + azureSdkForJs: false + isCadlTest: true + isModularLibrary: true + enableOperationGroup: true + packageDetails: + name: "@msinternal/azure-collection-format" + description: "Azure Collection Format Test Service" From 273fe005e7efdd12c71784ccacfde2980b9d0f48 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 10:33:59 +0800 Subject: [PATCH 07/16] Change the names --- packages/typespec-ts/src/modular/buildClassicalClient.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/typespec-ts/src/modular/buildClassicalClient.ts b/packages/typespec-ts/src/modular/buildClassicalClient.ts index adf28655b5..9255ec2547 100644 --- a/packages/typespec-ts/src/modular/buildClassicalClient.ts +++ b/packages/typespec-ts/src/modular/buildClassicalClient.ts @@ -174,7 +174,7 @@ function buildClientOperationGroups( initializer: ` { ${operationDeclarations.map((d) => { - return `${getClassicalName(d)}: (${d.parameters + return `${getClassicalMethodName(d)}: (${d.parameters ?.filter((p) => p.name !== "context") .map( (p) => p.name + (p.name === "options" ? "?" : "") + ": " + p.type @@ -192,7 +192,7 @@ function buildClientOperationGroups( operationDeclarations.map((d) => { const method: MethodDeclarationStructure = { docs: d.docs, - name: getClassicalName(d), + name: getClassicalMethodName(d), kind: StructureKind.Method, returnType: d.returnType, parameters: d.parameters?.filter((p) => p.name !== "context"), @@ -210,7 +210,7 @@ function buildClientOperationGroups( } } - function getClassicalName( + function getClassicalMethodName( declaration: OptionalKind ) { return operationMap.get(declaration) ?? declaration.name ?? "FIXME"; From 17155da2097cf560c52623e0cc8a21f511dbc5f8 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 10:40:30 +0800 Subject: [PATCH 08/16] Update the lint fixes --- packages/typespec-ts/src/utils/operationUtil.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/typespec-ts/src/utils/operationUtil.ts b/packages/typespec-ts/src/utils/operationUtil.ts index 23184e3b6e..3b99050ceb 100644 --- a/packages/typespec-ts/src/utils/operationUtil.ts +++ b/packages/typespec-ts/src/utils/operationUtil.ts @@ -355,11 +355,11 @@ export function getSpecialSerializeInfo( paramType: string, paramFormat: string ) { - let hasMultiCollection = getHasMultiCollection(paramType, paramFormat); - let hasPipeCollection = getHasPipeCollection(paramType, paramFormat); - let hasSsvCollection = getHasSsvCollection(paramType, paramFormat); - let hasTsvCollection = getHasTsvCollection(paramType, paramFormat); - let hasCsvCollection = getHasCsvCollection(paramType, paramFormat); + const hasMultiCollection = getHasMultiCollection(paramType, paramFormat); + const hasPipeCollection = getHasPipeCollection(paramType, paramFormat); + const hasSsvCollection = getHasSsvCollection(paramType, paramFormat); + const hasTsvCollection = getHasTsvCollection(paramType, paramFormat); + const hasCsvCollection = getHasCsvCollection(paramType, paramFormat); const descriptions = []; const collectionInfo = []; if (hasMultiCollection) { From a80f11177ad8100e098f82427b89c022c569b01c Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 11:16:00 +0800 Subject: [PATCH 09/16] Regen smoke-test --- .../typespec-ts/review/authoring.api.md | 30 +++++++++---------- .../typespec-ts/src/clientDefinitions.ts | 8 +++-- .../generated/typespec-ts/src/isUnexpected.ts | 17 ++++++----- .../typespec-ts/src/pollingHelper.ts | 8 ++--- .../generated/typespec-ts/src/responses.ts | 12 ++++---- 5 files changed, 40 insertions(+), 35 deletions(-) diff --git a/packages/typespec-test/test/authoring/generated/typespec-ts/review/authoring.api.md b/packages/typespec-test/test/authoring/generated/typespec-ts/review/authoring.api.md index d063776da0..c31be791f5 100644 --- a/packages/typespec-test/test/authoring/generated/typespec-ts/review/authoring.api.md +++ b/packages/typespec-test/test/authoring/generated/typespec-ts/review/authoring.api.md @@ -268,43 +268,43 @@ export type DeployProjectParameters = DeployProjectBodyParam & RequestParameters // @public (undocumented) export interface Export { - post(options: ExportParameters): StreamableMethod; + post(options: ExportParameters): StreamableMethod; +} + +// @public +export interface ExportLogicalResponse extends HttpResponse { + // (undocumented) + status: "200"; } // @public (undocumented) -export interface Export202Headers { +export interface ExportOperation202Headers { "operation-location": string; } // @public -export interface Export202Response extends HttpResponse { +export interface ExportOperation202Response extends HttpResponse { // (undocumented) - headers: RawHttpHeaders & Export202Headers; + headers: RawHttpHeaders & ExportOperation202Headers; // (undocumented) status: "202"; } // @public (undocumented) -export interface ExportDefaultHeaders { +export interface ExportOperationDefaultHeaders { "x-ms-error-code"?: string; } // @public (undocumented) -export interface ExportDefaultResponse extends HttpResponse { +export interface ExportOperationDefaultResponse extends HttpResponse { // (undocumented) body: ErrorResponse; // (undocumented) - headers: RawHttpHeaders & ExportDefaultHeaders; + headers: RawHttpHeaders & ExportOperationDefaultHeaders; // (undocumented) status: string; } -// @public -export interface ExportLogicalResponse extends HttpResponse { - // (undocumented) - status: "200"; -} - // @public (undocumented) export type ExportParameters = ExportQueryParam & RequestParameters; @@ -416,7 +416,7 @@ export function getLongRunningPoller(client: Client, initialResponse: DeleteOperation202Response | DeleteOperationDefaultResponse, options?: CreateHttpPollerOptions>): Promise, TResult>>; // @public (undocumented) -export function getLongRunningPoller(client: Client, initialResponse: Export202Response | ExportDefaultResponse, options?: CreateHttpPollerOptions>): Promise, TResult>>; +export function getLongRunningPoller(client: Client, initialResponse: ExportOperation202Response | ExportOperationDefaultResponse, options?: CreateHttpPollerOptions>): Promise, TResult>>; // @public (undocumented) export function getLongRunningPoller(client: Client, initialResponse: Importx202Response | ImportxDefaultResponse, options?: CreateHttpPollerOptions>): Promise, TResult>>; @@ -572,7 +572,7 @@ export function isUnexpected(response: DeleteOperation202Response | DeleteLogica export function isUnexpected(response: ListProjects200Response | ListProjectsDefaultResponse): response is ListProjectsDefaultResponse; // @public (undocumented) -export function isUnexpected(response: Export202Response | ExportLogicalResponse | ExportDefaultResponse): response is ExportDefaultResponse; +export function isUnexpected(response: ExportOperation202Response | ExportLogicalResponse | ExportOperationDefaultResponse): response is ExportOperationDefaultResponse; // @public (undocumented) export function isUnexpected(response: Importx202Response | ImportxLogicalResponse | ImportxDefaultResponse): response is ImportxDefaultResponse; diff --git a/packages/typespec-test/test/authoring/generated/typespec-ts/src/clientDefinitions.ts b/packages/typespec-test/test/authoring/generated/typespec-ts/src/clientDefinitions.ts index d402838e3d..2b91a95e58 100644 --- a/packages/typespec-test/test/authoring/generated/typespec-ts/src/clientDefinitions.ts +++ b/packages/typespec-test/test/authoring/generated/typespec-ts/src/clientDefinitions.ts @@ -29,8 +29,8 @@ import { DeleteOperationDefaultResponse, ListProjects200Response, ListProjectsDefaultResponse, - Export202Response, - ExportDefaultResponse, + ExportOperation202Response, + ExportOperationDefaultResponse, Importx202Response, ImportxDefaultResponse, Train202Response, @@ -89,7 +89,9 @@ export interface Export { /** Triggers a job to export a project's data. */ post( options: ExportParameters - ): StreamableMethod; + ): StreamableMethod< + ExportOperation202Response | ExportOperationDefaultResponse + >; } export interface Importx { diff --git a/packages/typespec-test/test/authoring/generated/typespec-ts/src/isUnexpected.ts b/packages/typespec-test/test/authoring/generated/typespec-ts/src/isUnexpected.ts index e1ae1e2c30..1625709e2c 100644 --- a/packages/typespec-test/test/authoring/generated/typespec-ts/src/isUnexpected.ts +++ b/packages/typespec-test/test/authoring/generated/typespec-ts/src/isUnexpected.ts @@ -13,9 +13,9 @@ import { DeleteOperationDefaultResponse, ListProjects200Response, ListProjectsDefaultResponse, - Export202Response, + ExportOperation202Response, ExportLogicalResponse, - ExportDefaultResponse, + ExportOperationDefaultResponse, Importx202Response, ImportxLogicalResponse, ImportxDefaultResponse, @@ -101,8 +101,11 @@ export function isUnexpected( response: ListProjects200Response | ListProjectsDefaultResponse ): response is ListProjectsDefaultResponse; export function isUnexpected( - response: Export202Response | ExportLogicalResponse | ExportDefaultResponse -): response is ExportDefaultResponse; + response: + | ExportOperation202Response + | ExportLogicalResponse + | ExportOperationDefaultResponse +): response is ExportOperationDefaultResponse; export function isUnexpected( response: Importx202Response | ImportxLogicalResponse | ImportxDefaultResponse ): response is ImportxDefaultResponse; @@ -165,9 +168,9 @@ export function isUnexpected( | DeleteOperationDefaultResponse | ListProjects200Response | ListProjectsDefaultResponse - | Export202Response + | ExportOperation202Response | ExportLogicalResponse - | ExportDefaultResponse + | ExportOperationDefaultResponse | Importx202Response | ImportxLogicalResponse | ImportxDefaultResponse @@ -201,7 +204,7 @@ export function isUnexpected( | GetDefaultResponse | DeleteOperationDefaultResponse | ListProjectsDefaultResponse - | ExportDefaultResponse + | ExportOperationDefaultResponse | ImportxDefaultResponse | TrainDefaultResponse | GetDeploymentDefaultResponse diff --git a/packages/typespec-test/test/authoring/generated/typespec-ts/src/pollingHelper.ts b/packages/typespec-test/test/authoring/generated/typespec-ts/src/pollingHelper.ts index 0e5b3e2998..431817085f 100644 --- a/packages/typespec-test/test/authoring/generated/typespec-ts/src/pollingHelper.ts +++ b/packages/typespec-test/test/authoring/generated/typespec-ts/src/pollingHelper.ts @@ -18,8 +18,8 @@ import { DeleteOperation202Response, DeleteOperationDefaultResponse, DeleteLogicalResponse, - Export202Response, - ExportDefaultResponse, + ExportOperation202Response, + ExportOperationDefaultResponse, ExportLogicalResponse, Importx202Response, ImportxDefaultResponse, @@ -63,10 +63,10 @@ export async function getLongRunningPoller< options?: CreateHttpPollerOptions> ): Promise, TResult>>; export async function getLongRunningPoller< - TResult extends ExportLogicalResponse | ExportDefaultResponse + TResult extends ExportLogicalResponse | ExportOperationDefaultResponse >( client: Client, - initialResponse: Export202Response | ExportDefaultResponse, + initialResponse: ExportOperation202Response | ExportOperationDefaultResponse, options?: CreateHttpPollerOptions> ): Promise, TResult>>; export async function getLongRunningPoller< diff --git a/packages/typespec-test/test/authoring/generated/typespec-ts/src/responses.ts b/packages/typespec-test/test/authoring/generated/typespec-ts/src/responses.ts index a572374f0c..0e940679ef 100644 --- a/packages/typespec-test/test/authoring/generated/typespec-ts/src/responses.ts +++ b/packages/typespec-test/test/authoring/generated/typespec-ts/src/responses.ts @@ -119,26 +119,26 @@ export interface ListProjectsDefaultResponse extends HttpResponse { headers: RawHttpHeaders & ListProjectsDefaultHeaders; } -export interface Export202Headers { +export interface ExportOperation202Headers { /** The location for monitoring the operation state. */ "operation-location": string; } /** The request has been accepted for processing, but processing has not yet completed. */ -export interface Export202Response extends HttpResponse { +export interface ExportOperation202Response extends HttpResponse { status: "202"; - headers: RawHttpHeaders & Export202Headers; + headers: RawHttpHeaders & ExportOperation202Headers; } -export interface ExportDefaultHeaders { +export interface ExportOperationDefaultHeaders { /** String error code indicating what went wrong. */ "x-ms-error-code"?: string; } -export interface ExportDefaultResponse extends HttpResponse { +export interface ExportOperationDefaultResponse extends HttpResponse { status: string; body: ErrorResponse; - headers: RawHttpHeaders & ExportDefaultHeaders; + headers: RawHttpHeaders & ExportOperationDefaultHeaders; } /** The final response for long-running export operation */ From 9c56ee1c6cc13f4e8502b3c78e506e267b518fa0 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 11:34:26 +0800 Subject: [PATCH 10/16] Format the code --- .../src/transform/transformParameters.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/typespec-ts/src/transform/transformParameters.ts b/packages/typespec-ts/src/transform/transformParameters.ts index 2dc6b93ee3..fff5800bd7 100644 --- a/packages/typespec-ts/src/transform/transformParameters.ts +++ b/packages/typespec-ts/src/transform/transformParameters.ts @@ -141,7 +141,10 @@ function getParameterMetadata( type === "number[]" || type === "Array" ) { - const serializeInfo = getSpecialSerializeInfo(parameter.type, (parameter as any).format); + const serializeInfo = getSpecialSerializeInfo( + parameter.type, + (parameter as any).format + ); if ( serializeInfo.hasMultiCollection || serializeInfo.hasPipeCollection || @@ -154,10 +157,11 @@ function getParameterMetadata( ", " )} collection, we provide ${serializeInfo.descriptions.join( ", " - )} from serializeHelper.ts to help${serializeInfo.hasMultiCollection - ? ", you will probably need to set skipUrlEncoding as true when sending the request" - : "" - }`; + )} from serializeHelper.ts to help${ + serializeInfo.hasMultiCollection + ? ", you will probably need to set skipUrlEncoding as true when sending the request" + : "" + }`; } } return { From 2e8cc8ef27f0cdaeea089697a4eb69bfcb254d02 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 13:09:38 +0800 Subject: [PATCH 11/16] Regenerate the integration testings --- .../azure/core/src/clientDefinitions.ts | 8 ++++--- .../generated/azure/core/src/isUnexpected.ts | 14 +++++------ .../generated/azure/core/src/responses.ts | 8 +++---- .../lro/lroCore/src/clientDefinitions.ts | 8 ++++--- .../generated/lro/lroCore/src/isUnexpected.ts | 17 +++++++------ .../lro/lroCore/src/pollingHelper.ts | 8 +++---- .../generated/lro/lroCore/src/responses.ts | 12 +++++----- .../src/RenamedOperationClient.ts | 12 +++++----- .../renamed-operation/src/api/group.ts | 18 +++++++------- .../structure/renamed-operation/src/index.ts | 6 ++--- .../renamed-operation/src/models/index.ts | 6 ++--- .../renamed-operation/src/models/options.ts | 6 ++--- .../src/TwoOperationGroupClient.ts | 24 +++++++++---------- .../two-operation-group/src/api/group1.ts | 18 ++++++-------- .../two-operation-group/src/api/group2.ts | 18 ++++++-------- .../two-operation-group/src/index.ts | 12 +++++----- .../two-operation-group/src/models/index.ts | 12 +++++----- .../two-operation-group/src/models/options.ts | 12 +++++----- 18 files changed, 109 insertions(+), 110 deletions(-) diff --git a/packages/typespec-ts/test/integration/generated/azure/core/src/clientDefinitions.ts b/packages/typespec-ts/test/integration/generated/azure/core/src/clientDefinitions.ts index 35c0fffb5a..aa7ba2ffd5 100644 --- a/packages/typespec-ts/test/integration/generated/azure/core/src/clientDefinitions.ts +++ b/packages/typespec-ts/test/integration/generated/azure/core/src/clientDefinitions.ts @@ -28,8 +28,8 @@ import { ListWithPageDefaultResponse, ListWithCustomPageModel200Response, ListWithCustomPageModelDefaultResponse, - Export200Response, - ExportDefaultResponse, + ExportOperation200Response, + ExportOperationDefaultResponse, } from "./responses"; import { Client, StreamableMethod } from "@azure-rest/core-client"; @@ -89,7 +89,9 @@ export interface Export { /** Exports a User */ post( options: ExportParameters - ): StreamableMethod; + ): StreamableMethod< + ExportOperation200Response | ExportOperationDefaultResponse + >; } export interface Routes { diff --git a/packages/typespec-ts/test/integration/generated/azure/core/src/isUnexpected.ts b/packages/typespec-ts/test/integration/generated/azure/core/src/isUnexpected.ts index 365e8f757b..f4bdd561e0 100644 --- a/packages/typespec-ts/test/integration/generated/azure/core/src/isUnexpected.ts +++ b/packages/typespec-ts/test/integration/generated/azure/core/src/isUnexpected.ts @@ -18,8 +18,8 @@ import { ListWithPageDefaultResponse, ListWithCustomPageModel200Response, ListWithCustomPageModelDefaultResponse, - Export200Response, - ExportDefaultResponse, + ExportOperation200Response, + ExportOperationDefaultResponse, } from "./responses"; const responseMap: Record = { @@ -63,8 +63,8 @@ export function isUnexpected( | ListWithCustomPageModelDefaultResponse ): response is ListWithCustomPageModelDefaultResponse; export function isUnexpected( - response: Export200Response | ExportDefaultResponse -): response is ExportDefaultResponse; + response: ExportOperation200Response | ExportOperationDefaultResponse +): response is ExportOperationDefaultResponse; export function isUnexpected( response: | CreateOrUpdate200Response @@ -83,8 +83,8 @@ export function isUnexpected( | ListWithPageDefaultResponse | ListWithCustomPageModel200Response | ListWithCustomPageModelDefaultResponse - | Export200Response - | ExportDefaultResponse + | ExportOperation200Response + | ExportOperationDefaultResponse ): response is | CreateOrUpdateDefaultResponse | CreateOrReplaceDefaultResponse @@ -93,7 +93,7 @@ export function isUnexpected( | ListDefaultResponse | ListWithPageDefaultResponse | ListWithCustomPageModelDefaultResponse - | ExportDefaultResponse { + | ExportOperationDefaultResponse { const lroOriginal = response.headers["x-ms-original-url"]; const url = new URL(lroOriginal ?? response.request.url); const method = response.request.method; diff --git a/packages/typespec-ts/test/integration/generated/azure/core/src/responses.ts b/packages/typespec-ts/test/integration/generated/azure/core/src/responses.ts index f0295eb3b9..28a2d7dddf 100644 --- a/packages/typespec-ts/test/integration/generated/azure/core/src/responses.ts +++ b/packages/typespec-ts/test/integration/generated/azure/core/src/responses.ts @@ -140,18 +140,18 @@ export interface DeleteOperationDefaultResponse extends HttpResponse { } /** The request has succeeded. */ -export interface Export200Response extends HttpResponse { +export interface ExportOperation200Response extends HttpResponse { status: "200"; body: UserOutput; } -export interface ExportDefaultHeaders { +export interface ExportOperationDefaultHeaders { /** String error code indicating what went wrong. */ "x-ms-error-code"?: string; } -export interface ExportDefaultResponse extends HttpResponse { +export interface ExportOperationDefaultResponse extends HttpResponse { status: string; body: ErrorResponse; - headers: RawHttpHeaders & ExportDefaultHeaders; + headers: RawHttpHeaders & ExportOperationDefaultHeaders; } diff --git a/packages/typespec-ts/test/integration/generated/lro/lroCore/src/clientDefinitions.ts b/packages/typespec-ts/test/integration/generated/lro/lroCore/src/clientDefinitions.ts index 5effa096ef..eb52cca672 100644 --- a/packages/typespec-ts/test/integration/generated/lro/lroCore/src/clientDefinitions.ts +++ b/packages/typespec-ts/test/integration/generated/lro/lroCore/src/clientDefinitions.ts @@ -12,8 +12,8 @@ import { CreateOrReplaceDefaultResponse, DeleteOperation202Response, DeleteOperationDefaultResponse, - Export202Response, - ExportDefaultResponse, + ExportOperation202Response, + ExportOperationDefaultResponse, } from "./responses"; import { Client, StreamableMethod } from "@azure-rest/core-client"; @@ -38,7 +38,9 @@ export interface Export { /** Exports a User */ post( options: ExportParameters - ): StreamableMethod; + ): StreamableMethod< + ExportOperation202Response | ExportOperationDefaultResponse + >; } export interface Routes { diff --git a/packages/typespec-ts/test/integration/generated/lro/lroCore/src/isUnexpected.ts b/packages/typespec-ts/test/integration/generated/lro/lroCore/src/isUnexpected.ts index 4bec8e7b2d..8b64f777dc 100644 --- a/packages/typespec-ts/test/integration/generated/lro/lroCore/src/isUnexpected.ts +++ b/packages/typespec-ts/test/integration/generated/lro/lroCore/src/isUnexpected.ts @@ -9,9 +9,9 @@ import { DeleteOperation202Response, DeleteLogicalResponse, DeleteOperationDefaultResponse, - Export202Response, + ExportOperation202Response, ExportLogicalResponse, - ExportDefaultResponse, + ExportOperationDefaultResponse, } from "./responses"; const responseMap: Record = { @@ -36,8 +36,11 @@ export function isUnexpected( | DeleteOperationDefaultResponse ): response is DeleteOperationDefaultResponse; export function isUnexpected( - response: Export202Response | ExportLogicalResponse | ExportDefaultResponse -): response is ExportDefaultResponse; + response: + | ExportOperation202Response + | ExportLogicalResponse + | ExportOperationDefaultResponse +): response is ExportOperationDefaultResponse; export function isUnexpected( response: | CreateOrReplace200Response @@ -47,13 +50,13 @@ export function isUnexpected( | DeleteOperation202Response | DeleteLogicalResponse | DeleteOperationDefaultResponse - | Export202Response + | ExportOperation202Response | ExportLogicalResponse - | ExportDefaultResponse + | ExportOperationDefaultResponse ): response is | CreateOrReplaceDefaultResponse | DeleteOperationDefaultResponse - | ExportDefaultResponse { + | ExportOperationDefaultResponse { const lroOriginal = response.headers["x-ms-original-url"]; const url = new URL(lroOriginal ?? response.request.url); const method = response.request.method; diff --git a/packages/typespec-ts/test/integration/generated/lro/lroCore/src/pollingHelper.ts b/packages/typespec-ts/test/integration/generated/lro/lroCore/src/pollingHelper.ts index a127202187..c79e3e0797 100644 --- a/packages/typespec-ts/test/integration/generated/lro/lroCore/src/pollingHelper.ts +++ b/packages/typespec-ts/test/integration/generated/lro/lroCore/src/pollingHelper.ts @@ -18,8 +18,8 @@ import { DeleteOperation202Response, DeleteOperationDefaultResponse, DeleteLogicalResponse, - Export202Response, - ExportDefaultResponse, + ExportOperation202Response, + ExportOperationDefaultResponse, ExportLogicalResponse, } from "./responses"; /** @@ -30,10 +30,10 @@ import { * @returns - A poller object to poll for operation state updates and eventually get the final response. */ export async function getLongRunningPoller< - TResult extends ExportLogicalResponse | ExportDefaultResponse + TResult extends ExportLogicalResponse | ExportOperationDefaultResponse >( client: Client, - initialResponse: Export202Response | ExportDefaultResponse, + initialResponse: ExportOperation202Response | ExportOperationDefaultResponse, options?: CreateHttpPollerOptions> ): Promise, TResult>>; export async function getLongRunningPoller< diff --git a/packages/typespec-ts/test/integration/generated/lro/lroCore/src/responses.ts b/packages/typespec-ts/test/integration/generated/lro/lroCore/src/responses.ts index e4d80f506b..de0c5ad17a 100644 --- a/packages/typespec-ts/test/integration/generated/lro/lroCore/src/responses.ts +++ b/packages/typespec-ts/test/integration/generated/lro/lroCore/src/responses.ts @@ -79,27 +79,27 @@ export interface DeleteLogicalResponse extends HttpResponse { body: OperationStatusOutput; } -export interface Export202Headers { +export interface ExportOperation202Headers { /** The location for monitoring the operation state. */ "operation-location": string; } /** The request has been accepted for processing, but processing has not yet completed. */ -export interface Export202Response extends HttpResponse { +export interface ExportOperation202Response extends HttpResponse { status: "202"; body: ResourceOperationStatusOutput; - headers: RawHttpHeaders & Export202Headers; + headers: RawHttpHeaders & ExportOperation202Headers; } -export interface ExportDefaultHeaders { +export interface ExportOperationDefaultHeaders { /** String error code indicating what went wrong. */ "x-ms-error-code"?: string; } -export interface ExportDefaultResponse extends HttpResponse { +export interface ExportOperationDefaultResponse extends HttpResponse { status: string; body: ErrorResponse; - headers: RawHttpHeaders & ExportDefaultHeaders; + headers: RawHttpHeaders & ExportOperationDefaultHeaders; } /** The final response for long-running export operation */ diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/RenamedOperationClient.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/RenamedOperationClient.ts index 4fafdd1bbf..32cfa08342 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/RenamedOperationClient.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/RenamedOperationClient.ts @@ -3,9 +3,9 @@ import { ClientType } from "./models/models.js"; import { - GroupRenamedTwoOptions, - GroupRenamedFourOptions, - GroupRenamedSixOptions, + RenamedTwoOptions, + RenamedFourOptions, + RenamedSixOptions, RenamedOneOptions, RenamedThreeOptions, RenamedFiveOptions, @@ -32,13 +32,13 @@ export class RenamedOperationClient { } group = { - renamedTwo: (options?: GroupRenamedTwoOptions): Promise => { + renamedTwo: (options?: RenamedTwoOptions): Promise => { return renamedTwo(this._client, options); }, - renamedFour: (options?: GroupRenamedFourOptions): Promise => { + renamedFour: (options?: RenamedFourOptions): Promise => { return renamedFour(this._client, options); }, - renamedSix: (options?: GroupRenamedSixOptions): Promise => { + renamedSix: (options?: RenamedSixOptions): Promise => { return renamedSix(this._client, options); }, }; diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/api/group.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/api/group.ts index ec9582df1b..ede3650fc3 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/api/group.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/api/group.ts @@ -12,14 +12,14 @@ import { operationOptionsToRequestParameters, } from "@azure-rest/core-client"; import { - GroupRenamedTwoOptions, - GroupRenamedFourOptions, - GroupRenamedSixOptions, + RenamedTwoOptions, + RenamedFourOptions, + RenamedSixOptions, } from "../models/options.js"; export function _renamedTwoSend( context: Client, - options: GroupRenamedTwoOptions = { requestOptions: {} } + options: RenamedTwoOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/two") @@ -34,7 +34,7 @@ export async function _renamedTwoDeserialize( export async function renamedTwo( context: Client, - options: GroupRenamedTwoOptions = { requestOptions: {} } + options: RenamedTwoOptions = { requestOptions: {} } ): Promise { const result = await _renamedTwoSend(context, options); return _renamedTwoDeserialize(result); @@ -42,7 +42,7 @@ export async function renamedTwo( export function _renamedFourSend( context: Client, - options: GroupRenamedFourOptions = { requestOptions: {} } + options: RenamedFourOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/four") @@ -57,7 +57,7 @@ export async function _renamedFourDeserialize( export async function renamedFour( context: Client, - options: GroupRenamedFourOptions = { requestOptions: {} } + options: RenamedFourOptions = { requestOptions: {} } ): Promise { const result = await _renamedFourSend(context, options); return _renamedFourDeserialize(result); @@ -65,7 +65,7 @@ export async function renamedFour( export function _renamedSixSend( context: Client, - options: GroupRenamedSixOptions = { requestOptions: {} } + options: RenamedSixOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/six") @@ -80,7 +80,7 @@ export async function _renamedSixDeserialize( export async function renamedSix( context: Client, - options: GroupRenamedSixOptions = { requestOptions: {} } + options: RenamedSixOptions = { requestOptions: {} } ): Promise { const result = await _renamedSixSend(context, options); return _renamedSixDeserialize(result); diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/index.ts index abd0d8fa49..19cc4f3085 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/index.ts @@ -7,9 +7,9 @@ export { } from "./RenamedOperationClient.js"; export { ClientType, - GroupRenamedTwoOptions, - GroupRenamedFourOptions, - GroupRenamedSixOptions, + RenamedTwoOptions, + RenamedFourOptions, + RenamedSixOptions, RenamedOneOptions, RenamedThreeOptions, RenamedFiveOptions, diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/models/index.ts index ffec77df83..3e885c55d0 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/models/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/models/index.ts @@ -3,9 +3,9 @@ export { ClientType } from "./models.js"; export { - GroupRenamedTwoOptions, - GroupRenamedFourOptions, - GroupRenamedSixOptions, + RenamedTwoOptions, + RenamedFourOptions, + RenamedSixOptions, RenamedOneOptions, RenamedThreeOptions, RenamedFiveOptions, diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/models/options.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/models/options.ts index 8a82417cfa..5a54b4c0f7 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/models/options.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/renamed-operation/src/models/options.ts @@ -3,11 +3,11 @@ import { OperationOptions } from "@azure-rest/core-client"; -export interface GroupRenamedTwoOptions extends OperationOptions {} +export interface RenamedTwoOptions extends OperationOptions {} -export interface GroupRenamedFourOptions extends OperationOptions {} +export interface RenamedFourOptions extends OperationOptions {} -export interface GroupRenamedSixOptions extends OperationOptions {} +export interface RenamedSixOptions extends OperationOptions {} export interface RenamedOneOptions extends OperationOptions {} diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/TwoOperationGroupClient.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/TwoOperationGroupClient.ts index 72bba29767..d3e5abda70 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/TwoOperationGroupClient.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/TwoOperationGroupClient.ts @@ -3,12 +3,12 @@ import { ClientType } from "./models/models.js"; import { - Group1OneOptions, - Group1ThreeOptions, - Group1FourOptions, - Group2TwoOptions, - Group2FiveOptions, - Group2SixOptions, + OneOptions, + ThreeOptions, + FourOptions, + TwoOptions, + FiveOptions, + SixOptions, } from "./models/options.js"; import { one, @@ -35,24 +35,24 @@ export class TwoOperationGroupClient { } group1 = { - one: (options?: Group1OneOptions): Promise => { + one: (options?: OneOptions): Promise => { return one(this._client, options); }, - three: (options?: Group1ThreeOptions): Promise => { + three: (options?: ThreeOptions): Promise => { return three(this._client, options); }, - four: (options?: Group1FourOptions): Promise => { + four: (options?: FourOptions): Promise => { return four(this._client, options); }, }; group2 = { - two: (options?: Group2TwoOptions): Promise => { + two: (options?: TwoOptions): Promise => { return two(this._client, options); }, - five: (options?: Group2FiveOptions): Promise => { + five: (options?: FiveOptions): Promise => { return five(this._client, options); }, - six: (options?: Group2SixOptions): Promise => { + six: (options?: SixOptions): Promise => { return six(this._client, options); }, }; diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/api/group1.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/api/group1.ts index 0e6ea7ebcc..5f1bc052d9 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/api/group1.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/api/group1.ts @@ -11,15 +11,11 @@ import { StreamableMethod, operationOptionsToRequestParameters, } from "@azure-rest/core-client"; -import { - Group1OneOptions, - Group1ThreeOptions, - Group1FourOptions, -} from "../models/options.js"; +import { OneOptions, ThreeOptions, FourOptions } from "../models/options.js"; export function _oneSend( context: Client, - options: Group1OneOptions = { requestOptions: {} } + options: OneOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/one") @@ -32,7 +28,7 @@ export async function _oneDeserialize(_result: One204Response): Promise { export async function one( context: Client, - options: Group1OneOptions = { requestOptions: {} } + options: OneOptions = { requestOptions: {} } ): Promise { const result = await _oneSend(context, options); return _oneDeserialize(result); @@ -40,7 +36,7 @@ export async function one( export function _threeSend( context: Client, - options: Group1ThreeOptions = { requestOptions: {} } + options: ThreeOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/three") @@ -55,7 +51,7 @@ export async function _threeDeserialize( export async function three( context: Client, - options: Group1ThreeOptions = { requestOptions: {} } + options: ThreeOptions = { requestOptions: {} } ): Promise { const result = await _threeSend(context, options); return _threeDeserialize(result); @@ -63,7 +59,7 @@ export async function three( export function _fourSend( context: Client, - options: Group1FourOptions = { requestOptions: {} } + options: FourOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/four") @@ -78,7 +74,7 @@ export async function _fourDeserialize( export async function four( context: Client, - options: Group1FourOptions = { requestOptions: {} } + options: FourOptions = { requestOptions: {} } ): Promise { const result = await _fourSend(context, options); return _fourDeserialize(result); diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/api/group2.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/api/group2.ts index e94630824c..07b27d11cb 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/api/group2.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/api/group2.ts @@ -11,15 +11,11 @@ import { StreamableMethod, operationOptionsToRequestParameters, } from "@azure-rest/core-client"; -import { - Group2TwoOptions, - Group2FiveOptions, - Group2SixOptions, -} from "../models/options.js"; +import { TwoOptions, FiveOptions, SixOptions } from "../models/options.js"; export function _twoSend( context: Client, - options: Group2TwoOptions = { requestOptions: {} } + options: TwoOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/two") @@ -32,7 +28,7 @@ export async function _twoDeserialize(_result: Two204Response): Promise { export async function two( context: Client, - options: Group2TwoOptions = { requestOptions: {} } + options: TwoOptions = { requestOptions: {} } ): Promise { const result = await _twoSend(context, options); return _twoDeserialize(result); @@ -40,7 +36,7 @@ export async function two( export function _fiveSend( context: Client, - options: Group2FiveOptions = { requestOptions: {} } + options: FiveOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/five") @@ -55,7 +51,7 @@ export async function _fiveDeserialize( export async function five( context: Client, - options: Group2FiveOptions = { requestOptions: {} } + options: FiveOptions = { requestOptions: {} } ): Promise { const result = await _fiveSend(context, options); return _fiveDeserialize(result); @@ -63,7 +59,7 @@ export async function five( export function _sixSend( context: Client, - options: Group2SixOptions = { requestOptions: {} } + options: SixOptions = { requestOptions: {} } ): StreamableMethod { return context .path("/six") @@ -76,7 +72,7 @@ export async function _sixDeserialize(_result: Six204Response): Promise { export async function six( context: Client, - options: Group2SixOptions = { requestOptions: {} } + options: SixOptions = { requestOptions: {} } ): Promise { const result = await _sixSend(context, options); return _sixDeserialize(result); diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/index.ts index eb8f396943..13603a007d 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/index.ts @@ -7,10 +7,10 @@ export { } from "./TwoOperationGroupClient.js"; export { ClientType, - Group1OneOptions, - Group1ThreeOptions, - Group1FourOptions, - Group2TwoOptions, - Group2FiveOptions, - Group2SixOptions, + OneOptions, + ThreeOptions, + FourOptions, + TwoOptions, + FiveOptions, + SixOptions, } from "./models/index.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/models/index.ts index 24827c0b84..297beca02a 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/models/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/models/index.ts @@ -3,10 +3,10 @@ export { ClientType } from "./models.js"; export { - Group1OneOptions, - Group1ThreeOptions, - Group1FourOptions, - Group2TwoOptions, - Group2FiveOptions, - Group2SixOptions, + OneOptions, + ThreeOptions, + FourOptions, + TwoOptions, + FiveOptions, + SixOptions, } from "./options.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/models/options.ts b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/models/options.ts index 99493095b2..232303204a 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/models/options.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/client/structure/two-operation-group/src/models/options.ts @@ -3,14 +3,14 @@ import { OperationOptions } from "@azure-rest/core-client"; -export interface Group1OneOptions extends OperationOptions {} +export interface OneOptions extends OperationOptions {} -export interface Group1ThreeOptions extends OperationOptions {} +export interface ThreeOptions extends OperationOptions {} -export interface Group1FourOptions extends OperationOptions {} +export interface FourOptions extends OperationOptions {} -export interface Group2TwoOptions extends OperationOptions {} +export interface TwoOptions extends OperationOptions {} -export interface Group2FiveOptions extends OperationOptions {} +export interface FiveOptions extends OperationOptions {} -export interface Group2SixOptions extends OperationOptions {} +export interface SixOptions extends OperationOptions {} From 8cb943304453caa3fb6089778468f12599f107d7 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 17:32:19 +0800 Subject: [PATCH 12/16] Update the code to detect conflicts in RLC --- .../src/transform/transfromRLCOptions.ts | 74 +++++++++++++++++-- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/packages/typespec-ts/src/transform/transfromRLCOptions.ts b/packages/typespec-ts/src/transform/transfromRLCOptions.ts index fb4e25d914..2318898552 100644 --- a/packages/typespec-ts/src/transform/transfromRLCOptions.ts +++ b/packages/typespec-ts/src/transform/transfromRLCOptions.ts @@ -5,12 +5,22 @@ import { RLCOptions, ServiceInfo } from "@azure-tools/rlc-common"; -import { getDoc, NoTarget, Program } from "@typespec/compiler"; -import { getAuthentication } from "@typespec/http"; +import { + getDoc, + ignoreDiagnostics, + NoTarget, + Program +} from "@typespec/compiler"; +import { getAuthentication, getHttpOperation } from "@typespec/http"; import { reportDiagnostic } from "../lib.js"; import { getDefaultService } from "../utils/modelUtils.js"; import { getRLCClients } from "../utils/clientUtils.js"; import { SdkContext } from "../utils/interfaces.js"; +import { + listOperationGroups, + listOperationsInOperationGroup +} from "@azure-tools/typespec-client-generator-core"; +import { getOperationName } from "../utils/operationUtil.js"; export function transformRLCOptions( emitterOptions: RLCOptions, @@ -18,7 +28,7 @@ export function transformRLCOptions( ): RLCOptions { // Extract the options from emitter option const options = extractRLCOptions( - dpgContext.program, + dpgContext, emitterOptions, dpgContext.generationPathDetail?.rootDir ?? "" ); @@ -28,10 +38,11 @@ export function transformRLCOptions( } function extractRLCOptions( - program: Program, + dpgContext: SdkContext, emitterOptions: RLCOptions, generationRootDir: string ): RLCOptions { + const program = dpgContext.program; const includeShortcuts = getIncludeShortcuts(emitterOptions); const packageDetails = getPackageDetails(program, emitterOptions); const serviceInfo = getServiceInfo(program); @@ -41,7 +52,10 @@ function extractRLCOptions( const generateTest: undefined | boolean = getGenerateTest(emitterOptions); const credentialInfo = getCredentialInfo(program, emitterOptions); const azureOutputDirectory = getAzureOutputDirectory(generationRootDir); - const enableOperationGroup = getEnableOperationGroup(emitterOptions); + const enableOperationGroup = getEnableOperationGroup( + dpgContext, + emitterOptions + ); return { ...emitterOptions, ...credentialInfo, @@ -112,10 +126,54 @@ function processAuth(program: Program) { return securityInfo; } -function getEnableOperationGroup(emitterOptions: RLCOptions) { - if (emitterOptions.enableOperationGroup === true) { - return true; +function getEnableOperationGroup( + dpgContext: SdkContext, + emitterOptions: RLCOptions +) { + if ( + emitterOptions.enableOperationGroup === true || + emitterOptions.enableOperationGroup === false + ) { + return emitterOptions.enableOperationGroup; } + // Detect if existing name conflicts if customers didn't set the option explicitly + return detectIfNameConflicts(dpgContext); +} + +function detectIfNameConflicts(dpgContext: SdkContext) { + const clients = getRLCClients(dpgContext); + const program = dpgContext.program; + const nameSet = new Set(); + for (const client of clients) { + const operationGroups = listOperationGroups(dpgContext, client); + for (const operationGroup of operationGroups) { + const operations = listOperationsInOperationGroup( + dpgContext, + operationGroup + ); + for (const op of operations) { + const route = ignoreDiagnostics(getHttpOperation(program, op)); + const name = getOperationName(program, route.operation); + if (nameSet.has(name)) { + return true; + } else { + nameSet.add(name); + } + } + } + const clientOperations = listOperationsInOperationGroup(dpgContext, client); + for (const clientOp of clientOperations) { + const route = ignoreDiagnostics(getHttpOperation(program, clientOp)); + const name = getOperationName(program, route.operation); + if (nameSet.has(name)) { + return true; + } else { + nameSet.add(name); + } + } + } + + // No conflicts if we didn't detect any return false; } From 3b934857c093074d3df47079833e42cfe7b5d0c7 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 17:34:00 +0800 Subject: [PATCH 13/16] Remove the option because we detect in our code --- .../generated/parameters/collection-format/tspconfig.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/tspconfig.yaml b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/tspconfig.yaml index 3303e165fb..0724bca4a0 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/tspconfig.yaml +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/tspconfig.yaml @@ -9,7 +9,6 @@ options: azureSdkForJs: false isCadlTest: true isModularLibrary: true - enableOperationGroup: true packageDetails: name: "@msinternal/azure-collection-format" description: "Azure Collection Format Test Service" From f2dd4c59274eb927750a25eff1831c0be7777dae Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 17:38:57 +0800 Subject: [PATCH 14/16] Remove useless smoke testing --- .../generated/typespec-ts/.eslintrc.json | 11 -- .../generated/typespec-ts/README.md | 57 -------- .../generated/typespec-ts/api-extractor.json | 18 --- .../generated/typespec-ts/karma.conf.js | 133 ------------------ .../generated/typespec-ts/package.json | 103 -------------- .../review/collection-format.api.md | 90 ------------ .../generated/typespec-ts/rollup.config.js | 118 ---------------- .../typespec-ts/src/clientDefinitions.ts | 25 ---- .../src/collectionFormatTestService.ts | 41 ------ .../generated/typespec-ts/src/index.ts | 12 -- .../generated/typespec-ts/src/logger.ts | 5 - .../generated/typespec-ts/src/parameters.ts | 25 ---- .../generated/typespec-ts/src/responses.ts | 16 --- .../typespec-ts/src/serializeHelper.ts | 13 -- .../test/public/sampleTest.spec.ts | 23 --- .../test/public/utils/env.browser.ts | 2 - .../typespec-ts/test/public/utils/env.ts | 6 - .../test/public/utils/recordedClient.ts | 29 ---- .../generated/typespec-ts/tsconfig.json | 25 ---- .../test/collectionFormat/spec/main.tsp | 30 ---- .../test/collectionFormat/tspconfig.yaml | 12 -- 21 files changed, 794 deletions(-) delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/.eslintrc.json delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/README.md delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/api-extractor.json delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/karma.conf.js delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/package.json delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/review/collection-format.api.md delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/rollup.config.js delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/clientDefinitions.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/collectionFormatTestService.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/index.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/logger.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/parameters.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/responses.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/serializeHelper.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/sampleTest.spec.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/env.browser.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/env.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/recordedClient.ts delete mode 100644 packages/typespec-test/test/collectionFormat/generated/typespec-ts/tsconfig.json delete mode 100644 packages/typespec-test/test/collectionFormat/spec/main.tsp delete mode 100644 packages/typespec-test/test/collectionFormat/tspconfig.yaml diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/.eslintrc.json b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/.eslintrc.json deleted file mode 100644 index 619797ac39..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/.eslintrc.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "plugins": ["@azure/azure-sdk"], - "extends": ["plugin:@azure/azure-sdk/azure-sdk-base"], - "rules": { - "@azure/azure-sdk/ts-modules-only-named": "warn", - "@azure/azure-sdk/ts-apiextractor-json-types": "warn", - "@azure/azure-sdk/ts-package-json-types": "warn", - "@azure/azure-sdk/ts-package-json-engine-is-present": "warn", - "tsdoc/syntax": "warn" - } -} diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/README.md b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/README.md deleted file mode 100644 index d191f3044f..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Azure CollectionFormatTesting REST client library for JavaScript - -Collection Format Test Service - -**Please rely heavily on our [REST client docs](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/rest-clients.md) to use this library** - -Key links: - -- [Package (NPM)](https://www.npmjs.com/package/@azure-rest/collection-format) -- [API reference documentation](https://docs.microsoft.com/javascript/api/@azure-rest/collection-format?view=azure-node-preview) - -## Getting started - -### Currently supported environments - -- LTS versions of Node.js - -### Prerequisites - -- You must have an [Azure subscription](https://azure.microsoft.com/free/) to use this package. - -### Install the `@azure-rest/collection-format` package - -Install the Azure CollectionFormatTesting REST client REST client library for JavaScript with `npm`: - -```bash -npm install @azure-rest/collection-format -``` - -### Create and authenticate a `CollectionFormatTestServiceClient` - -To use an [Azure Active Directory (AAD) token credential](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/identity/identity/samples/AzureIdentityExamples.md#authenticating-with-a-pre-fetched-access-token), -provide an instance of the desired credential type obtained from the -[@azure/identity](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials) library. - -To authenticate with AAD, you must first `npm` install [`@azure/identity`](https://www.npmjs.com/package/@azure/identity) - -After setup, you can choose which type of [credential](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials) from `@azure/identity` to use. -As an example, [DefaultAzureCredential](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#defaultazurecredential) -can be used to authenticate the client. - -Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: -AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET - -## Troubleshooting - -### Logging - -Enabling logging may help uncover useful information about failures. In order to see a log of HTTP requests and responses, set the `AZURE_LOG_LEVEL` environment variable to `info`. Alternatively, logging can be enabled at runtime by calling `setLogLevel` in the `@azure/logger`: - -```javascript -const { setLogLevel } = require("@azure/logger"); - -setLogLevel("info"); -``` - -For more detailed instructions on how to enable logs, you can look at the [@azure/logger package docs](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger). diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/api-extractor.json b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/api-extractor.json deleted file mode 100644 index a7920c9eca..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/api-extractor.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "./types/src/index.d.ts", - "docModel": { "enabled": true }, - "apiReport": { "enabled": true, "reportFolder": "./review" }, - "dtsRollup": { - "enabled": true, - "untrimmedFilePath": "", - "publicTrimmedFilePath": "./types/collection-format.d.ts" - }, - "messages": { - "tsdocMessageReporting": { "default": { "logLevel": "none" } }, - "extractorMessageReporting": { - "ae-missing-release-tag": { "logLevel": "none" }, - "ae-unresolved-link": { "logLevel": "none" } - } - } -} diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/karma.conf.js b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/karma.conf.js deleted file mode 100644 index a9d5f1b5fc..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/karma.conf.js +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -// https://github.com/karma-runner/karma-chrome-launcher -process.env.CHROME_BIN = require("puppeteer").executablePath(); -require("dotenv").config(); -const { relativeRecordingsPath } = require("@azure-tools/test-recorder"); -process.env.RECORDINGS_RELATIVE_PATH = relativeRecordingsPath(); - -module.exports = function (config) { - config.set({ - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: "./", - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ["source-map-support", "mocha"], - - plugins: [ - "karma-mocha", - "karma-mocha-reporter", - "karma-chrome-launcher", - "karma-firefox-launcher", - "karma-env-preprocessor", - "karma-coverage", - "karma-sourcemap-loader", - "karma-junit-reporter", - "karma-source-map-support", - ], - - // list of files / patterns to load in the browser - files: [ - "dist-test/index.browser.js", - { - pattern: "dist-test/index.browser.js.map", - type: "html", - included: false, - served: true, - }, - ], - - // list of files / patterns to exclude - exclude: [], - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - "**/*.js": ["sourcemap", "env"], - // IMPORTANT: COMMENT following line if you want to debug in your browsers!! - // Preprocess source file to calculate code coverage, however this will make source file unreadable - // "dist-test/index.js": ["coverage"] - }, - - envPreprocessor: [ - "TEST_MODE", - "ENDPOINT", - "AZURE_CLIENT_SECRET", - "AZURE_CLIENT_ID", - "AZURE_TENANT_ID", - "SUBSCRIPTION_ID", - "RECORDINGS_RELATIVE_PATH", - ], - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ["mocha", "coverage", "junit"], - - coverageReporter: { - // specify a common output directory - dir: "coverage-browser/", - reporters: [ - { type: "json", subdir: ".", file: "coverage.json" }, - { type: "lcovonly", subdir: ".", file: "lcov.info" }, - { type: "html", subdir: "html" }, - { type: "cobertura", subdir: ".", file: "cobertura-coverage.xml" }, - ], - }, - - junitReporter: { - outputDir: "", // results will be saved as $outputDir/$browserName.xml - outputFile: "test-results.browser.xml", // if included, results will be saved as $outputDir/$browserName/$outputFile - suite: "", // suite will become the package name attribute in xml testsuite element - useBrowserName: false, // add browser name to report and classes names - nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element - classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element - properties: {}, // key value pair of properties to add to the section of the report - }, - - // web server port - port: 9876, - - // enable / disable colors in the output (reporters and logs) - colors: true, - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, - - // --no-sandbox allows our tests to run in Linux without having to change the system. - // --disable-web-security allows us to authenticate from the browser without having to write tests using interactive auth, which would be far more complex. - browsers: ["ChromeHeadlessNoSandbox"], - customLaunchers: { - ChromeHeadlessNoSandbox: { - base: "ChromeHeadless", - flags: ["--no-sandbox", "--disable-web-security"], - }, - }, - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: false, - - // Concurrency level - // how many browser should be started simultaneous - concurrency: 1, - - browserNoActivityTimeout: 60000000, - browserDisconnectTimeout: 10000, - browserDisconnectTolerance: 3, - - client: { - mocha: { - // change Karma's debug.html to the mocha web reporter - reporter: "html", - timeout: "600000", - }, - }, - }); -}; diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/package.json b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/package.json deleted file mode 100644 index f1b3989e65..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/package.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "name": "@azure-rest/collection-format", - "sdk-type": "client", - "author": "Microsoft Corporation", - "version": "1.0.0-beta.1", - "description": "Collection Format Test Service", - "keywords": ["node", "azure", "cloud", "typescript", "browser", "isomorphic"], - "license": "MIT", - "main": "dist/index.js", - "module": "./dist-esm/src/index.js", - "types": "./types/collection-format.d.ts", - "repository": "github:Azure/azure-sdk-for-js", - "bugs": { "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, - "files": [ - "dist/", - "dist-esm/src/", - "types/collection-format.d.ts", - "README.md", - "LICENSE", - "review/*" - ], - "engines": { "node": ">=14.0.0" }, - "scripts": { - "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", - "build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1", - "build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1", - "build:samples": "echo skipped.", - "build:test": "tsc -p . && rollup -c 2>&1", - "build:debug": "echo skipped.", - "check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"*.{js,json}\" \"test/**/*.ts\"", - "clean": "rimraf dist dist-browser dist-esm test-dist temp types *.tgz *.log", - "execute:samples": "echo skipped", - "extract-api": "rimraf review && mkdirp ./review && api-extractor run --local", - "format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"*.{js,json}\" \"test/**/*.ts\"", - "generate:client": "echo skipped", - "integration-test:browser": "karma start --single-run", - "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 5000000 --full-trace \"dist-esm/test/{,!(browser)/**/}*.spec.js\"", - "integration-test": "npm run integration-test:node && npm run integration-test:browser", - "lint:fix": "eslint package.json api-extractor.json src test --ext .ts --fix --fix-type [problem,suggestion]", - "lint": "eslint package.json api-extractor.json src test --ext .ts", - "pack": "npm pack 2>&1", - "test:browser": "npm run clean && npm run build:test && npm run unit-test:browser", - "test:node": "npm run clean && npm run build:test && npm run unit-test:node", - "test": "npm run clean && npm run build:test && npm run unit-test", - "unit-test": "npm run unit-test:node && npm run unit-test:browser", - "unit-test:node": "mocha -r esm --require ts-node/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 1200000 --full-trace \"test/{,!(browser)/**/}*.spec.ts\"", - "unit-test:browser": "karma start --single-run", - "build": "npm run clean && tsc && rollup -c 2>&1 && npm run minify && mkdirp ./review && npm run extract-api", - "minify": "uglifyjs -c -m --comments --source-map \"content='./dist/index.js.map'\" -o ./dist/index.min.js ./dist/index.js" - }, - "sideEffects": false, - "autoPublish": false, - "dependencies": { - "@azure/core-auth": "^1.3.0", - "@azure-rest/core-client": "^1.1.4", - "@azure/core-rest-pipeline": "^1.12.0", - "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" - }, - "devDependencies": { - "@microsoft/api-extractor": "^7.31.1", - "autorest": "latest", - "@types/node": "^14.0.0", - "dotenv": "^16.0.0", - "eslint": "^8.0.0", - "mkdirp": "^2.1.2", - "prettier": "^2.5.1", - "rimraf": "^3.0.0", - "source-map-support": "^0.5.9", - "typescript": "~5.0.0", - "@rollup/plugin-commonjs": "^24.0.0", - "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-multi-entry": "^6.0.0", - "@rollup/plugin-node-resolve": "^13.1.3", - "rollup": "^2.66.1", - "rollup-plugin-sourcemaps": "^0.6.3", - "uglify-js": "^3.4.9", - "@azure-tools/test-credential": "^1.0.0", - "@azure/identity": "^2.0.1", - "@azure-tools/test-recorder": "^3.0.0", - "mocha": "^7.1.1", - "@types/mocha": "^7.0.2", - "mocha-junit-reporter": "^1.18.0", - "cross-env": "^7.0.2", - "@types/chai": "^4.2.8", - "chai": "^4.2.0", - "karma-chrome-launcher": "^3.0.0", - "karma-coverage": "^2.0.0", - "karma-env-preprocessor": "^0.1.1", - "karma-firefox-launcher": "^2.1.2", - "karma-junit-reporter": "^2.0.1", - "karma-mocha-reporter": "^2.2.5", - "karma-mocha": "^2.0.1", - "karma-source-map-support": "~1.4.0", - "karma-sourcemap-loader": "^0.4.0", - "karma": "^6.2.0", - "nyc": "^15.0.0", - "ts-node": "^10.0.0" - }, - "browser": { - "./dist-esm/test/public/utils/env.js": "./dist-esm/test/public/utils/env.browser.js" - } -} diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/review/collection-format.api.md b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/review/collection-format.api.md deleted file mode 100644 index 6576bbd670..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/review/collection-format.api.md +++ /dev/null @@ -1,90 +0,0 @@ -## API Report File for "@azure-rest/collection-format" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { Client } from '@azure-rest/core-client'; -import { ClientOptions } from '@azure-rest/core-client'; -import { HttpResponse } from '@azure-rest/core-client'; -import { RequestParameters } from '@azure-rest/core-client'; -import { StreamableMethod } from '@azure-rest/core-client'; - -// @public (undocumented) -export function buildMultiCollection(items: string[], parameterName: string): string; - -// @public (undocumented) -export type CollectionFormatTestServiceClient = Client & { - path: Routes; -}; - -// @public -function createClient(endpoint: string, options?: ClientOptions): CollectionFormatTestServiceClient; -export default createClient; - -// @public (undocumented) -export interface Routes { - (path: "/collectionFormat/multi"): TestMulti; - (path: "/collectionFormat/csv"): TestCsv; -} - -// @public (undocumented) -export interface TestCsv { - // (undocumented) - get(options: TestCsvParameters): StreamableMethod; -} - -// @public -export interface TestCsv200Response extends HttpResponse { - // (undocumented) - body: string; - // (undocumented) - status: "200"; -} - -// @public (undocumented) -export type TestCsvParameters = TestCsvQueryParam & RequestParameters; - -// @public (undocumented) -export interface TestCsvQueryParam { - // (undocumented) - queryParameters: TestCsvQueryParamProperties; -} - -// @public (undocumented) -export interface TestCsvQueryParamProperties { - // (undocumented) - colors: string[]; -} - -// @public (undocumented) -export interface TestMulti { - // (undocumented) - get(options: TestMultiParameters): StreamableMethod; -} - -// @public -export interface TestMulti200Response extends HttpResponse { - // (undocumented) - body: string; - // (undocumented) - status: "200"; -} - -// @public (undocumented) -export type TestMultiParameters = TestMultiQueryParam & RequestParameters; - -// @public (undocumented) -export interface TestMultiQueryParam { - // (undocumented) - queryParameters: TestMultiQueryParamProperties; -} - -// @public (undocumented) -export interface TestMultiQueryParamProperties { - colors: string; -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/rollup.config.js b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/rollup.config.js deleted file mode 100644 index 61251d7a8d..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/rollup.config.js +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import nodeResolve from "@rollup/plugin-node-resolve"; -import cjs from "@rollup/plugin-commonjs"; -import sourcemaps from "rollup-plugin-sourcemaps"; -import multiEntry from "@rollup/plugin-multi-entry"; -import json from "@rollup/plugin-json"; - -import nodeBuiltins from "builtin-modules"; - -// #region Warning Handler - -/** - * A function that can determine whether a rollup warning should be ignored. If - * the function returns `true`, then the warning will not be displayed. - */ - -function ignoreNiseSinonEval(warning) { - return ( - warning.code === "EVAL" && - warning.id && - (warning.id.includes("node_modules/nise") || - warning.id.includes("node_modules/sinon")) === true - ); -} - -function ignoreChaiCircularDependency(warning) { - return ( - warning.code === "CIRCULAR_DEPENDENCY" && - warning.importer && - warning.importer.includes("node_modules/chai") === true - ); -} - -const warningInhibitors = [ignoreChaiCircularDependency, ignoreNiseSinonEval]; - -/** - * Construct a warning handler for the shared rollup configuration - * that ignores certain warnings that are not relevant to testing. - */ -function makeOnWarnForTesting() { - return (warning, warn) => { - // If every inhibitor returns false (i.e. no inhibitors), then show the warning - if (warningInhibitors.every((inhib) => !inhib(warning))) { - warn(warning); - } - }; -} - -// #endregion - -function makeBrowserTestConfig() { - const config = { - input: { - include: ["dist-esm/test/**/*.spec.js"], - exclude: ["dist-esm/test/**/node/**"], - }, - output: { - file: `dist-test/index.browser.js`, - format: "umd", - sourcemap: true, - }, - preserveSymlinks: false, - plugins: [ - multiEntry({ exports: false }), - nodeResolve({ - mainFields: ["module", "browser"], - }), - cjs(), - json(), - sourcemaps(), - //viz({ filename: "dist-test/browser-stats.html", sourcemap: true }) - ], - onwarn: makeOnWarnForTesting(), - // Disable tree-shaking of test code. In rollup-plugin-node-resolve@5.0.0, - // rollup started respecting the "sideEffects" field in package.json. Since - // our package.json sets "sideEffects=false", this also applies to test - // code, which causes all tests to be removed by tree-shaking. - treeshake: false, - }; - - return config; -} - -const defaultConfigurationOptions = { - disableBrowserBundle: false, -}; - -export function makeConfig(pkg, options) { - options = { - ...defaultConfigurationOptions, - ...(options || {}), - }; - - const baseConfig = { - // Use the package's module field if it has one - input: pkg["module"] || "dist-esm/src/index.js", - external: [ - ...nodeBuiltins, - ...Object.keys(pkg.dependencies), - ...Object.keys(pkg.devDependencies), - ], - output: { file: "dist/index.js", format: "cjs", sourcemap: true }, - preserveSymlinks: false, - plugins: [sourcemaps(), nodeResolve()], - }; - - const config = [baseConfig]; - - if (!options.disableBrowserBundle) { - config.push(makeBrowserTestConfig()); - } - - return config; -} - -export default makeConfig(require("./package.json")); diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/clientDefinitions.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/clientDefinitions.ts deleted file mode 100644 index 38d7f9024d..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/clientDefinitions.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { TestMultiParameters, TestCsvParameters } from "./parameters"; -import { TestMulti200Response, TestCsv200Response } from "./responses"; -import { Client, StreamableMethod } from "@azure-rest/core-client"; - -export interface TestMulti { - get(options: TestMultiParameters): StreamableMethod; -} - -export interface TestCsv { - get(options: TestCsvParameters): StreamableMethod; -} - -export interface Routes { - /** Resource for '/collectionFormat/multi' has methods for the following verbs: get */ - (path: "/collectionFormat/multi"): TestMulti; - /** Resource for '/collectionFormat/csv' has methods for the following verbs: get */ - (path: "/collectionFormat/csv"): TestCsv; -} - -export type CollectionFormatTestServiceClient = Client & { - path: Routes; -}; diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/collectionFormatTestService.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/collectionFormatTestService.ts deleted file mode 100644 index 9cbe0ffcf1..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/collectionFormatTestService.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { getClient, ClientOptions } from "@azure-rest/core-client"; -import { logger } from "./logger"; -import { CollectionFormatTestServiceClient } from "./clientDefinitions"; - -/** - * Initialize a new instance of `CollectionFormatTestServiceClient` - * @param endpoint - The parameter endpoint - * @param options - the parameter for all optional parameters - */ -export default function createClient( - endpoint: string, - options: ClientOptions = {} -): CollectionFormatTestServiceClient { - const baseUrl = options.baseUrl ?? `${endpoint}`; - options.apiVersion = options.apiVersion ?? "2022-12-16-preview"; - - const userAgentInfo = `azsdk-js-collection-format-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 CollectionFormatTestServiceClient; - - return client; -} diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/index.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/index.ts deleted file mode 100644 index f6139429a0..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import CollectionFormatTestService from "./collectionFormatTestService"; - -export * from "./collectionFormatTestService"; -export * from "./parameters"; -export * from "./responses"; -export * from "./clientDefinitions"; -export * from "./serializeHelper"; - -export default CollectionFormatTestService; diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/logger.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/logger.ts deleted file mode 100644 index c5ef751531..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/logger.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { createClientLogger } from "@azure/logger"; -export const logger = createClientLogger("collection-format"); diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/parameters.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/parameters.ts deleted file mode 100644 index c1919b1efe..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/parameters.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { RequestParameters } from "@azure-rest/core-client"; - -export interface TestMultiQueryParamProperties { - /** This parameter needs to be formatted as multi collection, we provide buildMultiCollection from serializeHelper.ts to help, you will probably need to set skipUrlEncoding as true when sending the request */ - colors: string; -} - -export interface TestMultiQueryParam { - queryParameters: TestMultiQueryParamProperties; -} - -export type TestMultiParameters = TestMultiQueryParam & RequestParameters; - -export interface TestCsvQueryParamProperties { - colors: string[]; -} - -export interface TestCsvQueryParam { - queryParameters: TestCsvQueryParamProperties; -} - -export type TestCsvParameters = TestCsvQueryParam & RequestParameters; diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/responses.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/responses.ts deleted file mode 100644 index 5e7ba6bc41..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/responses.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { HttpResponse } from "@azure-rest/core-client"; - -/** The request has succeeded. */ -export interface TestMulti200Response extends HttpResponse { - status: "200"; - body: string; -} - -/** The request has succeeded. */ -export interface TestCsv200Response extends HttpResponse { - status: "200"; - body: string; -} diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/serializeHelper.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/serializeHelper.ts deleted file mode 100644 index 710a5bf2a7..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/src/serializeHelper.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -export function buildMultiCollection(items: string[], parameterName: string) { - return items - .map((item, index) => { - if (index === 0) { - return item; - } - return `${parameterName}=${item}`; - }) - .join("&"); -} diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/sampleTest.spec.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/sampleTest.spec.ts deleted file mode 100644 index bce68e4286..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/sampleTest.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { Recorder } from "@azure-tools/test-recorder"; -import { assert } from "chai"; -import { createRecorder } from "./utils/recordedClient"; -import { Context } from "mocha"; - -describe("My test", () => { - let recorder: Recorder; - - beforeEach(async function (this: Context) { - recorder = await createRecorder(this); - }); - - afterEach(async function () { - await recorder.stop(); - }); - - it("sample test", async function () { - assert.equal(1, 1); - }); -}); diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/env.browser.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/env.browser.ts deleted file mode 100644 index fd2aca680c..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/env.browser.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/env.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/env.ts deleted file mode 100644 index 0e06855b73..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/env.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import * as dotenv from "dotenv"; - -dotenv.config(); diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/recordedClient.ts b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/recordedClient.ts deleted file mode 100644 index 6cc58bc15e..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/test/public/utils/recordedClient.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import { Context } from "mocha"; -import { Recorder, RecorderStartOptions } from "@azure-tools/test-recorder"; -import "./env"; - -const envSetupForPlayback: Record = { - ENDPOINT: "https://endpoint", - AZURE_CLIENT_ID: "azure_client_id", - AZURE_CLIENT_SECRET: "azure_client_secret", - AZURE_TENANT_ID: "88888888-8888-8888-8888-888888888888", - SUBSCRIPTION_ID: "azure_subscription_id", -}; - -const recorderEnvSetup: RecorderStartOptions = { - envSetupForPlayback, -}; - -/** - * creates the recorder and reads the environment variables from the `.env` file. - * Should be called first in the test suite to make sure environment variables are - * read before they are being used. - */ -export async function createRecorder(context: Context): Promise { - const recorder = new Recorder(context.currentTest); - await recorder.start(recorderEnvSetup); - return recorder; -} diff --git a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/tsconfig.json b/packages/typespec-test/test/collectionFormat/generated/typespec-ts/tsconfig.json deleted file mode 100644 index 9ca43fa318..0000000000 --- a/packages/typespec-test/test/collectionFormat/generated/typespec-ts/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "module": "es6", - "lib": [], - "declaration": true, - "declarationMap": true, - "inlineSources": true, - "sourceMap": true, - "importHelpers": true, - "strict": true, - "alwaysStrict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "forceConsistentCasingInFileNames": true, - "moduleResolution": "node", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true, - "outDir": "./dist-esm", - "declarationDir": "./types" - }, - "include": ["./src/**/*.ts", "./test/**/*.ts"] -} diff --git a/packages/typespec-test/test/collectionFormat/spec/main.tsp b/packages/typespec-test/test/collectionFormat/spec/main.tsp deleted file mode 100644 index a5dd900c41..0000000000 --- a/packages/typespec-test/test/collectionFormat/spec/main.tsp +++ /dev/null @@ -1,30 +0,0 @@ -import "@typespec/rest"; -import "@typespec/versioning"; - -using TypeSpec.Rest; -using TypeSpec.Http; -using TypeSpec.Versioning; - -@service({ - title: "Collection Format Testing", - version: "2022-12-16-preview", -}) - -namespace Azure.TypeScript.Testing; - -model MultiCollectionFormatParameter { - @query({ - format: "multi", - }) - colors: string[]; -} -model CsvCollectionFormatParameter { - @query({ - format: "csv", - }) - colors: string[]; -} -@route("/collectionFormat/multi") -op testMulti(...MultiCollectionFormatParameter): string; -@route("/collectionFormat/csv") -op testCsv(...CsvCollectionFormatParameter): string; \ No newline at end of file diff --git a/packages/typespec-test/test/collectionFormat/tspconfig.yaml b/packages/typespec-test/test/collectionFormat/tspconfig.yaml deleted file mode 100644 index 0709c61b85..0000000000 --- a/packages/typespec-test/test/collectionFormat/tspconfig.yaml +++ /dev/null @@ -1,12 +0,0 @@ -emit: - - "@azure-tools/typespec-ts" -options: - "@azure-tools/typespec-ts": - title: Collection Format Test Service - generateMetadata: true - azureSdkForJs: false - "emitter-output-dir": "{project-root}/generated/typespec-ts" - packageDetails: - name: "@azure-rest/collection-format" - description: "Collection Format Test Service" - version: "1.0.0-beta.1" From 10d4bf59da09ae234e6aa5f476b9f1eaafbeae09 Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 17:47:40 +0800 Subject: [PATCH 15/16] Remove the empty models.ts file --- packages/typespec-ts/src/modular/emitModels.ts | 14 +++++++++----- .../src/CollectionFormatClient.ts | 17 ++++++++--------- .../collection-format/src/models/index.ts | 1 - .../collection-format/src/models/models.ts | 2 -- 4 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/models.ts diff --git a/packages/typespec-ts/src/modular/emitModels.ts b/packages/typespec-ts/src/modular/emitModels.ts index c9e36faca9..c165cfcf27 100644 --- a/packages/typespec-ts/src/modular/emitModels.ts +++ b/packages/typespec-ts/src/modular/emitModels.ts @@ -13,17 +13,21 @@ export function buildModels( project: Project, srcPath: string = "src", subfolder: string = "" -): SourceFile { - const modelsFile = project.createSourceFile( - path.join(`${srcPath}/`, subfolder, `models/models.ts`) - ); - +): SourceFile | undefined { // We are generating both models and enums here const coreClientTypes = new Set(); const models = codeModel.types.filter( (t) => (t.type === "model" || t.type === "enum") && !isAzureCoreError(t) ); + // Skip to generate models.ts if there is no any models + if (models.length === 0) { + return; + } + const modelsFile = project.createSourceFile( + path.join(`${srcPath}/`, subfolder, `models/models.ts`) + ); + for (const model of codeModel.types) { if (model.type === "combined" && model.nullable) { for (const unionModel of model.types ?? []) { diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/CollectionFormatClient.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/CollectionFormatClient.ts index 7dbc343a55..3a93ab2309 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/CollectionFormatClient.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/CollectionFormatClient.ts @@ -1,15 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "./models/models.js"; -import { - QueryMultiOptions, - QuerySsvOptions, - QueryTsvOptions, - QueryPipesOptions, - QueryCsvOptions, - HeaderCsvOptions, -} from "./models/options.js"; import { createCollectionFormat, CollectionFormatClientOptions, @@ -21,6 +12,14 @@ import { queryPipes, queryCsv, } from "./api/index.js"; +import { + QueryMultiOptions, + QuerySsvOptions, + QueryTsvOptions, + QueryPipesOptions, + QueryCsvOptions, + HeaderCsvOptions, +} from "./models/options.js"; export { CollectionFormatClientOptions } from "./api/CollectionFormatContext.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/index.ts index 2565f14b07..a2f9a190cc 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/index.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/index.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -export * from "./models.js"; export { QueryMultiOptions, QuerySsvOptions, diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/models.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/models.ts deleted file mode 100644 index fd2aca680c..0000000000 --- a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/models/models.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. From 965187d68c2c6955501de4f6f1e7e8b70093509b Mon Sep 17 00:00:00 2001 From: Mary Gao Date: Mon, 21 Aug 2023 22:06:01 +0800 Subject: [PATCH 16/16] Fix ci issue --- .../typespec-ts/src/modular/buildClassicalClient.ts | 10 ++++++---- packages/typespec-ts/src/modular/buildOperations.ts | 10 ++++++---- .../src/api/CollectionFormatContext.ts | 1 - .../parameters/collection-format/src/api/header.ts | 1 - .../parameters/collection-format/src/api/query.ts | 1 - 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/typespec-ts/src/modular/buildClassicalClient.ts b/packages/typespec-ts/src/modular/buildClassicalClient.ts index 9255ec2547..4143d4a6a9 100644 --- a/packages/typespec-ts/src/modular/buildClassicalClient.ts +++ b/packages/typespec-ts/src/modular/buildClassicalClient.ts @@ -116,10 +116,12 @@ function importAllModels( const exported = [...apiModels.getExportedDeclarations().keys()]; - clientFile.addImportDeclaration({ - moduleSpecifier: `./models/models.js`, - namedImports: exported - }); + if (exported.length > 0) { + clientFile.addImportDeclaration({ + moduleSpecifier: `./models/models.js`, + namedImports: exported + }); + } const apiModelsOptions = project.getSourceFile( `${srcPath}/${subfolder !== "" ? subfolder + "/" : ""}models/options.ts` diff --git a/packages/typespec-ts/src/modular/buildOperations.ts b/packages/typespec-ts/src/modular/buildOperations.ts index 79d96ab25d..5a712629d4 100644 --- a/packages/typespec-ts/src/modular/buildOperations.ts +++ b/packages/typespec-ts/src/modular/buildOperations.ts @@ -134,10 +134,12 @@ export function importModels( models.push(entry[0]); } - sourceFile.addImportDeclaration({ - moduleSpecifier: "../models/models.js", - namedImports: models - }); + if (models.length > 0) { + sourceFile.addImportDeclaration({ + moduleSpecifier: "../models/models.js", + namedImports: models + }); + } // Import all models and then let ts-morph clean up the unused ones // we can't fixUnusedIdentifiers here because the operaiton files are still being generated. diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/CollectionFormatContext.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/CollectionFormatContext.ts index 43356d2199..1df3bac0cd 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/CollectionFormatContext.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/CollectionFormatContext.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "../models/models.js"; import { ClientOptions } from "@azure-rest/core-client"; import { CollectionFormatContext } from "../rest/index.js"; import getClient from "../rest/index.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/header.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/header.ts index e419ae4632..713077c02e 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/header.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/header.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "../models/models.js"; import { buildCsvCollection, CollectionFormatContext as Client, diff --git a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/query.ts b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/query.ts index d6d3306868..9dc5b946b8 100644 --- a/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/query.ts +++ b/packages/typespec-ts/test/modularIntegration/generated/parameters/collection-format/src/api/query.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import "../models/models.js"; import { buildMultiCollection, buildPipeCollection,