diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index ee179fed1b..e76d3fb9bb 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -233,7 +233,7 @@ importers: ../../packages/typespec-ts: specifiers: '@azure-rest/core-client': ^2.3.1 - '@azure-tools/azure-http-specs': 0.1.0-alpha.31-dev.0 + '@azure-tools/azure-http-specs': 0.1.0-alpha.32-dev.1 '@azure-tools/rlc-common': workspace:^0.45.1 '@azure-tools/typespec-autorest': ^0.61.0 '@azure-tools/typespec-azure-core': ^0.61.0 @@ -297,7 +297,7 @@ importers: tslib: 2.6.2 devDependencies: '@azure-rest/core-client': 2.3.1 - '@azure-tools/azure-http-specs': 0.1.0-alpha.31-dev.0_mhtpjry45zcimvvqboa2mxannq + '@azure-tools/azure-http-specs': 0.1.0-alpha.32-dev.1_mhtpjry45zcimvvqboa2mxannq '@azure-tools/typespec-autorest': 0.61.0_zlxwjjyed53dbo4rv32x67ofpa '@azure-tools/typespec-azure-core': 0.61.0_eiv3q4yhoovesnkn4zu3754mpu '@azure-tools/typespec-azure-resource-manager': 0.61.0_574mczcc7t2su42jtuli7qb6cm @@ -473,8 +473,8 @@ packages: proper-lockfile: 2.0.1 dev: false - /@azure-tools/azure-http-specs/0.1.0-alpha.31-dev.0_mhtpjry45zcimvvqboa2mxannq: - resolution: {integrity: sha512-RyiGkg6GMkDPBuFCPAxbcQkg8rj/JrwlmICYwJcaT5LwbSSqiqBBYGhhIrd28vtfMun6szaP5j8V7ACGWzdHWQ==} + /@azure-tools/azure-http-specs/0.1.0-alpha.32-dev.1_mhtpjry45zcimvvqboa2mxannq: + resolution: {integrity: sha512-Kyy+xGK+m6jRacKLUwybXc0U0PQIrO8pkC/Zul9C3aehlIPBPrmmzltSjb+EU0XTrjlhiyjorGQ6rTdXTrOGqQ==} engines: {node: '>=20.0.0'} peerDependencies: '@azure-tools/typespec-azure-core': ^0.61.0 || >=0.62.0-dev <0.62.0 diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/LICENSE b/packages/typespec-test/test/testOperation/generated/typespec-ts/LICENSE deleted file mode 100644 index 63447fd8bb..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) Microsoft Corporation. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/README.md b/packages/typespec-test/test/testOperation/generated/typespec-ts/README.md deleted file mode 100644 index 640e1feeb6..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Azure KeyVault client library for JavaScript - -This package contains an isomorphic SDK (runs both in Node.js and in browsers) for Azure KeyVault client. - -Azure Key Vault Secrets - -Key links: - -- [Package (NPM)](https://www.npmjs.com/package/@azure/keyvault-secrets) -- [API reference documentation](https://learn.microsoft.com/javascript/api/@azure/keyvault-secrets?view=azure-node-preview) - -## Getting started - -### Currently supported environments - -- [LTS versions of Node.js](https://github.com/nodejs/release#release-schedule) -- Latest versions of Safari, Chrome, Edge and Firefox. - -See our [support policy](https://github.com/Azure/azure-sdk-for-js/blob/main/SUPPORT.md) for more details. - -### Prerequisites - -- An [Azure subscription][azure_sub]. - -### Install the `@azure/keyvault-secrets` package - -Install the Azure KeyVault client library for JavaScript with `npm`: - -```bash -npm install @azure/keyvault-secrets -``` - - - -### JavaScript Bundle -To use this client library in the browser, first you need to use a bundler. For details on how to do this, please refer to our [bundling documentation](https://aka.ms/AzureSDKBundling). - -## Key concepts - -### KeyVaultClient - -`KeyVaultClient` is the primary interface for developers using the Azure KeyVault client library. Explore the methods on this client object to understand the different features of the Azure KeyVault service that you can access. - -## 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`: - -```ts -import { setLogLevel } from "@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). - - -## Contributing - -If you'd like to contribute to this library, please read the [contributing guide](https://github.com/Azure/azure-sdk-for-js/blob/main/CONTRIBUTING.md) to learn more about how to build and test the code. - -## Related projects - -- [Microsoft Azure SDK for JavaScript](https://github.com/Azure/azure-sdk-for-js) - -[azure_sub]: https://azure.microsoft.com/free/ -[azure_portal]: https://portal.azure.com -[azure_identity]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity -[defaultazurecredential]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#defaultazurecredential diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/api-extractor.json b/packages/typespec-test/test/testOperation/generated/typespec-ts/api-extractor.json deleted file mode 100644 index e08bd809e5..0000000000 --- a/packages/typespec-test/test/testOperation/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": "dist/esm/index.d.ts", - "docModel": { "enabled": true }, - "apiReport": { "enabled": true, "reportFolder": "./review" }, - "dtsRollup": { - "enabled": true, - "untrimmedFilePath": "", - "publicTrimmedFilePath": "dist/keyvault-secrets.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/testOperation/generated/typespec-ts/eslint.config.mjs b/packages/typespec-test/test/testOperation/generated/typespec-ts/eslint.config.mjs deleted file mode 100644 index 9396819633..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/eslint.config.mjs +++ /dev/null @@ -1,14 +0,0 @@ -import azsdkEslint from "@azure/eslint-plugin-azure-sdk"; - -export default azsdkEslint.config([ - { - rules: { - "@azure/azure-sdk/ts-modules-only-named": "warn", - "@azure/azure-sdk/ts-package-json-types": "warn", - "@azure/azure-sdk/ts-package-json-engine-is-present": "warn", - "@azure/azure-sdk/ts-package-json-files-required": "off", - "@azure/azure-sdk/ts-package-json-main-is-cjs": "off", - "tsdoc/syntax": "warn" - } - } -]); diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/package.json b/packages/typespec-test/test/testOperation/generated/typespec-ts/package.json deleted file mode 100644 index 5765e51951..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/package.json +++ /dev/null @@ -1,132 +0,0 @@ -{ - "name": "@azure/keyvault-secrets", - "version": "1.0.0-beta.1", - "description": "Azure Key Vault Secrets", - "engines": { - "node": ">=20.0.0" - }, - "sideEffects": false, - "autoPublish": false, - "tshy": { - "exports": { - "./package.json": "./package.json", - ".": "./src/index.ts", - "./api": "./src/api/index.ts", - "./models": "./src/models/index.ts" - }, - "dialects": [ - "esm", - "commonjs" - ], - "esmDialects": [ - "browser", - "react-native" - ], - "selfLink": false - }, - "type": "module", - "browser": "./dist/browser/index.js", - "react-native": "./dist/react-native/index.js", - "keywords": [ - "node", - "azure", - "cloud", - "typescript", - "browser", - "isomorphic" - ], - "author": "Microsoft Corporation", - "license": "MIT", - "files": [ - "dist/", - "!dist/**/*.d.*ts.map", - "README.md", - "LICENSE" - ], - "dependencies": { - "@azure/core-util": "^1.9.2", - "@azure-rest/core-client": "^2.3.1", - "@azure/core-auth": "^1.6.0", - "@azure/core-rest-pipeline": "^1.5.0", - "@azure/logger": "^1.0.0", - "tslib": "^2.6.2" - }, - "devDependencies": { - "dotenv": "^16.0.0", - "@types/node": "^20.0.0", - "eslint": "^9.9.0", - "typescript": "~5.8.2", - "tshy": "^2.0.0", - "@microsoft/api-extractor": "^7.40.3", - "rimraf": "^5.0.5", - "mkdirp": "^3.0.1" - }, - "scripts": { - "clean": "rimraf --glob dist dist-browser dist-esm test-dist temp types *.tgz *.log", - "extract-api": "rimraf review && mkdirp ./review && api-extractor run --local", - "pack": "npm pack 2>&1", - "lint": "eslint package.json api-extractor.json src", - "lint:fix": "eslint package.json api-extractor.json src --fix --fix-type [problem,suggestion]", - "build": "npm run clean && tshy && npm run extract-api" - }, - "exports": { - "./package.json": "./package.json", - ".": { - "browser": { - "types": "./dist/browser/index.d.ts", - "default": "./dist/browser/index.js" - }, - "react-native": { - "types": "./dist/react-native/index.d.ts", - "default": "./dist/react-native/index.js" - }, - "import": { - "types": "./dist/esm/index.d.ts", - "default": "./dist/esm/index.js" - }, - "require": { - "types": "./dist/commonjs/index.d.ts", - "default": "./dist/commonjs/index.js" - } - }, - "./api": { - "browser": { - "types": "./dist/browser/api/index.d.ts", - "default": "./dist/browser/api/index.js" - }, - "react-native": { - "types": "./dist/react-native/api/index.d.ts", - "default": "./dist/react-native/api/index.js" - }, - "import": { - "types": "./dist/esm/api/index.d.ts", - "default": "./dist/esm/api/index.js" - }, - "require": { - "types": "./dist/commonjs/api/index.d.ts", - "default": "./dist/commonjs/api/index.js" - } - }, - "./models": { - "browser": { - "types": "./dist/browser/models/index.d.ts", - "default": "./dist/browser/models/index.js" - }, - "react-native": { - "types": "./dist/react-native/models/index.d.ts", - "default": "./dist/react-native/models/index.js" - }, - "import": { - "types": "./dist/esm/models/index.d.ts", - "default": "./dist/esm/models/index.js" - }, - "require": { - "types": "./dist/commonjs/models/index.d.ts", - "default": "./dist/commonjs/models/index.js" - } - } - }, - "main": "./dist/commonjs/index.js", - "types": "./dist/commonjs/index.d.ts", - "module": "./dist/esm/index.js" -} diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/review/keyvault-secrets.api.md b/packages/typespec-test/test/testOperation/generated/typespec-ts/review/keyvault-secrets.api.md deleted file mode 100644 index b0aaffbb68..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/review/keyvault-secrets.api.md +++ /dev/null @@ -1,34 +0,0 @@ -## API Report File for "@azure/keyvault-secrets" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts - -import { ClientOptions } from '@azure-rest/core-client'; -import { OperationOptions } from '@azure-rest/core-client'; -import { Pipeline } from '@azure/core-rest-pipeline'; - -// @public -export interface GetSecretOptionalParams extends OperationOptions { -} - -// @public (undocumented) -export class KeyVaultClient { - constructor(endpointParam: string, options?: KeyVaultClientOptionalParams); - getSecret(secretName: string, secretVersion: string, options?: GetSecretOptionalParams): Promise; - readonly pipeline: Pipeline; -} - -// @public -export interface KeyVaultClientOptionalParams extends ClientOptions { - apiVersion?: string; -} - -// @public -export enum KnownVersions { - V1 = "v1" -} - -// (No @packageDocumentation comment for this package) - -``` diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/rollup.config.js b/packages/typespec-test/test/testOperation/generated/typespec-ts/rollup.config.js deleted file mode 100644 index 843de501bf..0000000000 --- a/packages/typespec-test/test/testOperation/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/testOperation/generated/typespec-ts/sample.env b/packages/typespec-test/test/testOperation/generated/typespec-ts/sample.env deleted file mode 100644 index 508439fc7d..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/sample.env +++ /dev/null @@ -1 +0,0 @@ -# Feel free to add your own environment variables. \ No newline at end of file diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/index.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/index.ts deleted file mode 100644 index 9da08c6c76..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -export { - createKeyVault, - KeyVaultContext, - KeyVaultClientOptionalParams, -} from "./keyVaultContext.js"; -export { getSecret } from "./operations.js"; -export { GetSecretOptionalParams } from "./options.js"; diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/keyVaultContext.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/keyVaultContext.ts deleted file mode 100644 index 176395077d..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/keyVaultContext.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { logger } from "../logger.js"; -import { KnownVersions } from "../models/models.js"; -import { Client, ClientOptions, getClient } from "@azure-rest/core-client"; - -export interface KeyVaultContext extends Client { - /** The API version to use for this operation. */ - /** Known values of {@link KnownVersions} that the service accepts. */ - apiVersion: string; -} - -/** Optional parameters for the client. */ -export interface KeyVaultClientOptionalParams extends ClientOptions { - /** The API version to use for this operation. */ - /** Known values of {@link KnownVersions} that the service accepts. */ - apiVersion?: string; -} - -export function createKeyVault( - endpointParam: string, - options: KeyVaultClientOptionalParams = {}, -): KeyVaultContext { - const endpointUrl = options.endpoint ?? String(endpointParam); - const prefixFromOptions = options?.userAgentOptions?.userAgentPrefix; - const userAgentInfo = `azsdk-js-keyvault-secrets/1.0.0-beta.1`; - const userAgentPrefix = prefixFromOptions - ? `${prefixFromOptions} azsdk-js-api ${userAgentInfo}` - : `azsdk-js-api ${userAgentInfo}`; - const { apiVersion: _, ...updatedOptions } = { - ...options, - userAgentOptions: { userAgentPrefix }, - loggingOptions: { logger: options.loggingOptions?.logger ?? logger.info }, - }; - const clientContext = getClient(endpointUrl, undefined, updatedOptions); - clientContext.pipeline.removePolicy({ name: "ApiVersionPolicy" }); - const apiVersion = options.apiVersion ?? "v1"; - clientContext.pipeline.addPolicy({ - name: "ClientApiVersionPolicy", - sendRequest: (req, next) => { - // Use the apiVersion defined in request url directly - // Append one if there is no apiVersion and we have one at client options - const url = new URL(req.url); - if (!url.searchParams.get("api-version")) { - req.url = `${req.url}${ - Array.from(url.searchParams.keys()).length > 0 ? "&" : "?" - }api-version=${apiVersion}`; - } - - return next(req); - }, - }); - return { ...clientContext, apiVersion } as KeyVaultContext; -} diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/operations.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/operations.ts deleted file mode 100644 index a871bbe3c0..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/operations.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { KeyVaultContext as Client } from "./index.js"; -import { expandUrlTemplate } from "../static-helpers/urlTemplate.js"; -import { GetSecretOptionalParams } from "./options.js"; -import { - StreamableMethod, - PathUncheckedResponse, - createRestError, - operationOptionsToRequestParameters, -} from "@azure-rest/core-client"; - -export function _getSecretSend( - context: Client, - secretName: string, - secretVersion: string, - options: GetSecretOptionalParams = { requestOptions: {} }, -): StreamableMethod { - const path = expandUrlTemplate( - "/secrets/{secret-name}/{secret-version}{?api%2Dversion,outContentType}", - { - "secret-name": secretName, - "secret-version": secretVersion, - "api%2Dversion": context.apiVersion, - }, - { - allowReserved: options?.requestOptions?.skipUrlEncoding, - }, - ); - return context - .path(path) - .get({ ...operationOptionsToRequestParameters(options) }); -} - -export async function _getSecretDeserialize( - result: PathUncheckedResponse, -): Promise { - const expectedStatuses = ["200"]; - if (!expectedStatuses.includes(result.status)) { - throw createRestError(result); - } - - return; -} - -/** The most basic operation. */ -export async function getSecret( - context: Client, - secretName: string, - secretVersion: string, - options: GetSecretOptionalParams = { requestOptions: {} }, -): Promise { - const result = await _getSecretSend( - context, - secretName, - secretVersion, - options, - ); - return _getSecretDeserialize(result); -} diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/options.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/options.ts deleted file mode 100644 index 299ee7a8c9..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/api/options.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { OperationOptions } from "@azure-rest/core-client"; - -/** Optional parameters. */ -export interface GetSecretOptionalParams extends OperationOptions {} diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/index.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/index.ts deleted file mode 100644 index 2c4781047f..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -export { KeyVaultClient } from "./keyVaultClient.js"; -export { KnownVersions } from "./models/index.js"; -export { - KeyVaultClientOptionalParams, - GetSecretOptionalParams, -} from "./api/index.js"; diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/keyVaultClient.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/keyVaultClient.ts deleted file mode 100644 index 0ebc8cd430..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/keyVaultClient.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { - createKeyVault, - KeyVaultContext, - KeyVaultClientOptionalParams, -} from "./api/index.js"; -import { getSecret } from "./api/operations.js"; -import { GetSecretOptionalParams } from "./api/options.js"; -import { Pipeline } from "@azure/core-rest-pipeline"; - -export { KeyVaultClientOptionalParams } from "./api/keyVaultContext.js"; - -export class KeyVaultClient { - private _client: KeyVaultContext; - /** The pipeline used by this client to make requests */ - public readonly pipeline: Pipeline; - - constructor( - endpointParam: string, - options: KeyVaultClientOptionalParams = {}, - ) { - const prefixFromOptions = options?.userAgentOptions?.userAgentPrefix; - const userAgentPrefix = prefixFromOptions - ? `${prefixFromOptions} azsdk-js-client` - : `azsdk-js-client`; - this._client = createKeyVault(endpointParam, { - ...options, - userAgentOptions: { userAgentPrefix }, - }); - this.pipeline = this._client.pipeline; - } - - /** The most basic operation. */ - getSecret( - secretName: string, - secretVersion: string, - options: GetSecretOptionalParams = { requestOptions: {} }, - ): Promise { - return getSecret(this._client, secretName, secretVersion, options); - } -} diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/logger.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/logger.ts deleted file mode 100644 index 1e440642ca..0000000000 --- a/packages/typespec-test/test/testOperation/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("keyvault-secrets"); diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/models/index.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/models/index.ts deleted file mode 100644 index 0cc3e72d7e..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/models/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -export { KnownVersions } from "./models.js"; diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/models/models.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/models/models.ts deleted file mode 100644 index 8f4ea18437..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/models/models.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** Known values of {@link Versions} that the service accepts. */ -export enum KnownVersions { - /** v1 */ - V1 = "v1", -} diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/static-helpers/urlTemplate.ts b/packages/typespec-test/test/testOperation/generated/typespec-ts/src/static-helpers/urlTemplate.ts deleted file mode 100644 index 0a3e0d7372..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/src/static-helpers/urlTemplate.ts +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -// --------------------- -// interfaces -// --------------------- -interface ValueOptions { - isFirst: boolean; // is first value in the expression - op?: string; // operator - varValue?: any; // variable value - varName?: string; // variable name - modifier?: string; // modifier e.g * - reserved?: boolean; // if true we'll keep reserved words with not encoding -} - -export interface UrlTemplateOptions { - // if set to true, reserved characters will not be encoded - allowReserved?: boolean; -} - -// --------------------- -// helpers -// --------------------- -function encodeComponent(val: string, reserved?: boolean, op?: string): string { - return (reserved ?? op === "+") || op === "#" - ? encodeReservedComponent(val) - : encodeRFC3986URIComponent(val); -} - -function encodeReservedComponent(str: string): string { - return str - .split(/(%[0-9A-Fa-f]{2})/g) - .map((part) => (!/%[0-9A-Fa-f]/.test(part) ? encodeURI(part) : part)) - .join(""); -} - -function encodeRFC3986URIComponent(str: string): string { - return encodeURIComponent(str).replace( - /[!'()*]/g, - (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`, - ); -} - -function isDefined(val: any): boolean { - return val !== undefined && val !== null; -} - -function getNamedAndIfEmpty(op?: string): [boolean, string] { - return [ - !!op && [";", "?", "&"].includes(op), - !!op && ["?", "&"].includes(op) ? "=" : "", - ]; -} - -function getFirstOrSep(op?: string, isFirst = false): string { - if (isFirst) { - return !op || op === "+" ? "" : op; - } else if (!op || op === "+" || op === "#") { - return ","; - } else if (op === "?") { - return "&"; - } else { - return op; - } -} - -function getExpandedValue(option: ValueOptions): string { - let isFirst = option.isFirst; - const { op, varName, varValue: value, reserved } = option; - const vals: string[] = []; - const [named, ifEmpty] = getNamedAndIfEmpty(op); - - if (Array.isArray(value)) { - for (const val of value.filter(isDefined)) { - // prepare the following parts: separator, varName, value - vals.push(`${getFirstOrSep(op, isFirst)}`); - if (named && varName) { - vals.push(`${encodeURIComponent(varName)}`); - if (val === "") { - vals.push(ifEmpty); - } else { - vals.push("="); - } - } - vals.push(encodeComponent(val, reserved, op)); - isFirst = false; - } - } else if (typeof value === "object") { - for (const key of Object.keys(value)) { - const val = value[key]; - if (!isDefined(val)) { - continue; - } - // prepare the following parts: separator, key, value - vals.push(`${getFirstOrSep(op, isFirst)}`); - if (key) { - vals.push(`${encodeURIComponent(key)}`); - if (named && val === "") { - vals.push(ifEmpty); - } else { - vals.push("="); - } - } - vals.push(encodeComponent(val, reserved, op)); - isFirst = false; - } - } - return vals.join(""); -} - -function getNonExpandedValue(option: ValueOptions): string | undefined { - const { op, varName, varValue: value, isFirst, reserved } = option; - const vals: string[] = []; - const first = getFirstOrSep(op, isFirst); - const [named, ifEmpty] = getNamedAndIfEmpty(op); - if (named && varName) { - vals.push(encodeComponent(varName, reserved, op)); - if (value === "") { - if (!ifEmpty) { - vals.push(ifEmpty); - } - return !vals.join("") ? undefined : `${first}${vals.join("")}`; - } - vals.push("="); - } - - const items = []; - if (Array.isArray(value)) { - for (const val of value.filter(isDefined)) { - items.push(encodeComponent(val, reserved, op)); - } - } else if (typeof value === "object") { - for (const key of Object.keys(value)) { - if (!isDefined(value[key])) { - continue; - } - items.push(encodeRFC3986URIComponent(key)); - items.push(encodeComponent(value[key], reserved, op)); - } - } - vals.push(items.join(",")); - return !vals.join(",") ? undefined : `${first}${vals.join("")}`; -} - -function getVarValue(option: ValueOptions): string | undefined { - const { op, varName, modifier, isFirst, reserved, varValue: value } = option; - - if (!isDefined(value)) { - return undefined; - } else if (["string", "number", "boolean"].includes(typeof value)) { - let val = value.toString(); - const [named, ifEmpty] = getNamedAndIfEmpty(op); - const vals: string[] = [getFirstOrSep(op, isFirst)]; - if (named && varName) { - // No need to encode varName considering it is already encoded - vals.push(varName); - if (val === "") { - vals.push(ifEmpty); - } else { - vals.push("="); - } - } - if (modifier && modifier !== "*") { - val = val.substring(0, parseInt(modifier, 10)); - } - vals.push(encodeComponent(val, reserved, op)); - return vals.join(""); - } else if (modifier === "*") { - return getExpandedValue(option); - } else { - return getNonExpandedValue(option); - } -} - -// --------------------------------------------------------------------------------------------------- -// This is an implementation of RFC 6570 URI Template: https://datatracker.ietf.org/doc/html/rfc6570. -// --------------------------------------------------------------------------------------------------- -export function expandUrlTemplate( - template: string, - context: Record, - option?: UrlTemplateOptions, -): string { - return template.replace(/\{([^{}]+)\}|([^{}]+)/g, (_, expr, text) => { - if (!expr) { - return encodeReservedComponent(text); - } - let op; - if (["+", "#", ".", "/", ";", "?", "&"].includes(expr[0])) { - op = expr[0]; - expr = expr.slice(1); - } - const varList = expr.split(/,/g); - const result = []; - for (const varSpec of varList) { - const varMatch = /([^:*]*)(?::(\d+)|(\*))?/.exec(varSpec); - if (!varMatch || !varMatch[1]) { - continue; - } - const varValue = getVarValue({ - isFirst: result.length === 0, - op, - varValue: context[varMatch[1]], - varName: varMatch[1], - modifier: varMatch[2] || varMatch[3], - reserved: option?.allowReserved, - }); - if (varValue) { - result.push(varValue); - } - } - return result.join(""); - }); -} diff --git a/packages/typespec-test/test/testOperation/generated/typespec-ts/tsconfig.json b/packages/typespec-test/test/testOperation/generated/typespec-ts/tsconfig.json deleted file mode 100644 index 031889db45..0000000000 --- a/packages/typespec-test/test/testOperation/generated/typespec-ts/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "module": "NodeNext", - "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": "NodeNext", - "allowSyntheticDefaultImports": true, - "esModuleInterop": true - }, - "include": ["src/**/*.ts"] -} diff --git a/packages/typespec-test/test/testOperation/spec/client.tsp b/packages/typespec-test/test/testOperation/spec/client.tsp deleted file mode 100644 index 6b7e3f8255..0000000000 --- a/packages/typespec-test/test/testOperation/spec/client.tsp +++ /dev/null @@ -1,34 +0,0 @@ -import "./main.tsp"; -import "@azure-tools/typespec-client-generator-core"; - -using Azure.ClientGenerator.Core; -using TypeSpec.Http; - -namespace Customizations; -using KeyVault; - -/** - * The GET operation is applicable to any secret stored in Azure Key Vault. This operation requires the secrets/get permission. - */ -@summary("Get a specified secret from a given key vault.") -@route("/secrets/{secret-name}/{secret-version}") -@get -op getSecret is KeyVaultOperation< - { - /** - * The name of the secret. - */ - @path("secret-name") - @clientName("name", "go") - secretName: string; - - /** - * The version of the secret. This URI fragment is optional. If not specified, the latest version of the secret is returned. - */ - @path("secret-version") - @clientName("version", "go") - secretVersion: string; - }, - {} ->; -@@override(KeyVault.getSecret, getSecret); diff --git a/packages/typespec-test/test/testOperation/spec/main.tsp b/packages/typespec-test/test/testOperation/spec/main.tsp deleted file mode 100644 index 91cc83b469..0000000000 --- a/packages/typespec-test/test/testOperation/spec/main.tsp +++ /dev/null @@ -1,24 +0,0 @@ -import "@typespec/rest"; -import "@typespec/http"; -import "@typespec/versioning"; -import "@azure-tools/typespec-azure-core"; -import "./routes.tsp"; -import "@typespec/versioning"; - -using TypeSpec.Http; -using TypeSpec.Versioning; - -@service(#{ title: "KeyVaultClient" }) -@server( - "{vaultBaseUrl}", - "The key vault client performs cryptographic key operations and vault operations against the Key Vault service.", - { - vaultBaseUrl: url, - } -) -@versioned(Versions) -namespace KeyVault; - -enum Versions { - v1, -} diff --git a/packages/typespec-test/test/testOperation/spec/models.tsp b/packages/typespec-test/test/testOperation/spec/models.tsp deleted file mode 100644 index 5d1126d021..0000000000 --- a/packages/typespec-test/test/testOperation/spec/models.tsp +++ /dev/null @@ -1,11 +0,0 @@ -import "@azure-tools/typespec-azure-core"; - -using Azure.Core; - -namespace KeyVault; - -alias KeyVaultOperation< - TParams extends Reflection.Model, - TResponse, - Traits extends Reflection.Model = {} -> = Foundations.Operation; diff --git a/packages/typespec-test/test/testOperation/spec/routes.tsp b/packages/typespec-test/test/testOperation/spec/routes.tsp deleted file mode 100644 index 19dd3f63f7..0000000000 --- a/packages/typespec-test/test/testOperation/spec/routes.tsp +++ /dev/null @@ -1,37 +0,0 @@ -import "@azure-tools/typespec-azure-core"; -import "@azure-tools/typespec-client-generator-core"; -import "@typespec/rest"; -import "./models.tsp"; - -using Azure.ClientGenerator.Core; -using TypeSpec.Http; - -namespace KeyVault; - -@summary("Get a specified secret from a given key vault.") -@route("/secrets/{secret-name}/{secret-version}") -@get -op getSecret is KeyVaultOperation< - { - /** - * The name of the secret. - */ - @path("secret-name") - @clientName("name", "go") - secretName: string; - - /** - * The version of the secret. This URI fragment is optional. If not specified, the latest version of the secret is returned. - */ - @path("secret-version") - @clientName("version", "go") - secretVersion?: string; - - /** - * The media type (MIME type) of the certificate. If a supported format is specified, the certificate content is converted to the requested format. Currently, only PFX to PEM conversion is supported. If an unsupported format is specified, the request is rejected. If not specified, the certificate is returned in its original format without conversion. - */ - @query("outContentType") - outContentType?: string; - }, - {} ->; diff --git a/packages/typespec-test/test/testOperation/tsp-output/schema/openapi.v1.yaml b/packages/typespec-test/test/testOperation/tsp-output/schema/openapi.v1.yaml deleted file mode 100644 index da203dab95..0000000000 --- a/packages/typespec-test/test/testOperation/tsp-output/schema/openapi.v1.yaml +++ /dev/null @@ -1,57 +0,0 @@ -openapi: 3.1.0 -info: - title: KeyVaultClient - version: v1 -tags: [] -paths: - /secrets/{secret-name}/{secret-version}: - get: - operationId: getSecret - summary: Get a specified secret from a given key vault. - description: The most basic operation. - parameters: - - $ref: '#/components/parameters/Azure.Core.Foundations.ApiVersionParameter' - - name: secret-name - in: path - required: true - description: The name of the secret. - schema: - type: string - - name: secret-version - in: path - required: false - description: The version of the secret. This URI fragment is optional. If not specified, the latest version of the secret is returned. - schema: - type: string - - name: outContentType - in: query - required: false - description: The media type (MIME type) of the certificate. If a supported format is specified, the certificate content is converted to the requested format. Currently, only PFX to PEM conversion is supported. If an unsupported format is specified, the request is rejected. If not specified, the certificate is returned in its original format without conversion. - schema: - type: string - explode: false - responses: - '200': - description: The request has succeeded. -components: - parameters: - Azure.Core.Foundations.ApiVersionParameter: - name: api-version - in: query - required: true - description: The API version to use for this operation. - schema: - type: string - minLength: 1 - explode: false - schemas: - Versions: - type: string - enum: - - v1 -servers: - - url: '{vaultBaseUrl}' - description: The key vault client performs cryptographic key operations and vault operations against the Key Vault service. - variables: - vaultBaseUrl: - default: '' diff --git a/packages/typespec-test/test/testOperation/tsp-output/schema/openapi.yaml b/packages/typespec-test/test/testOperation/tsp-output/schema/openapi.yaml deleted file mode 100644 index 6a340a2c30..0000000000 --- a/packages/typespec-test/test/testOperation/tsp-output/schema/openapi.yaml +++ /dev/null @@ -1,52 +0,0 @@ -openapi: 3.1.0 -info: - title: KeyVaultClient - version: 0.0.0 -tags: [] -paths: - /secrets/{secret-name}/{secret-version}: - get: - operationId: getSecret - summary: Get a specified secret from a given key vault. - description: The most basic operation. - parameters: - - $ref: '#/components/parameters/Azure.Core.Foundations.ApiVersionParameter' - - name: secret-name - in: path - required: true - description: The name of the secret. - schema: - type: string - - name: secret-version - in: path - required: false - description: The version of the secret. This URI fragment is optional. If not specified, the latest version of the secret is returned. - schema: - type: string - - name: outContentType - in: query - required: false - description: The media type (MIME type) of the certificate. If a supported format is specified, the certificate content is converted to the requested format. Currently, only PFX to PEM conversion is supported. If an unsupported format is specified, the request is rejected. If not specified, the certificate is returned in its original format without conversion. - schema: - type: string - explode: false - responses: - '200': - description: The request has succeeded. -components: - parameters: - Azure.Core.Foundations.ApiVersionParameter: - name: api-version - in: query - required: true - description: The API version to use for this operation. - schema: - type: string - minLength: 1 - explode: false -servers: - - url: '{vaultBaseUrl}' - description: The key vault client performs cryptographic key operations and vault operations against the Key Vault service. - variables: - vaultBaseUrl: - default: '' diff --git a/packages/typespec-test/test/testOperation/tspconfig.yaml b/packages/typespec-test/test/testOperation/tspconfig.yaml deleted file mode 100644 index a750c5d27d..0000000000 --- a/packages/typespec-test/test/testOperation/tspconfig.yaml +++ /dev/null @@ -1,20 +0,0 @@ -emit: - - "@typespec/openapi3" - - "@azure-tools/typespec-ts" -options: - "@typespec/openapi3": - emitter-output-dir: "{output-dir}/schema" - openapi-versions: - - 3.1.0 - "@azure-tools/typespec-ts": - package-dir: "keyvault-secrets" - emitter-output-dir: "{project-root}/generated/typespec-ts" - generate-metadata: true - azure-sdk-for-js: false - # src-folder: "src/generated" - experimental-extensible-enums: true - is-modular-library: true - package-details: - name: "@azure/keyvault-secrets" - description: "Azure Key Vault Secrets" - flavor: azure \ No newline at end of file diff --git a/packages/typespec-ts/package.json b/packages/typespec-ts/package.json index 7a791ab695..183fe6441b 100644 --- a/packages/typespec-ts/package.json +++ b/packages/typespec-ts/package.json @@ -69,7 +69,7 @@ "@typespec/spector": "0.1.0-alpha.20-dev.0", "@typespec/spec-api": "0.1.0-alpha.10-dev.0", "@typespec/tspd": "0.73.0", - "@azure-tools/azure-http-specs": "0.1.0-alpha.31-dev.0", + "@azure-tools/azure-http-specs": "0.1.0-alpha.32-dev.1", "@azure-tools/typespec-autorest": "^0.61.0", "@azure-tools/typespec-azure-core": "^0.61.0", "@azure-tools/typespec-azure-resource-manager": "^0.61.0", diff --git a/packages/typespec-ts/src/modular/helpers/operationHelpers.ts b/packages/typespec-ts/src/modular/helpers/operationHelpers.ts index ba00129828..2894d46106 100644 --- a/packages/typespec-ts/src/modular/helpers/operationHelpers.ts +++ b/packages/typespec-ts/src/modular/helpers/operationHelpers.ts @@ -703,10 +703,16 @@ function getHeaderAndBodyParameters( ) { continue; } - parametersImplementation[param.kind].push({ - paramMap: getParameterMap(dpgContext, param, optionalParamName), - param - }); + // Check if this parameter still exists in the corresponding method params (after override) + if ( + param.correspondingMethodParams && + param.correspondingMethodParams.length > 0 + ) { + parametersImplementation[param.kind].push({ + paramMap: getParameterMap(dpgContext, param, optionalParamName), + param + }); + } } } diff --git a/packages/typespec-ts/test/azureIntegration/azureClientGeneratorCoreOverride.spec.ts b/packages/typespec-ts/test/azureIntegration/azureClientGeneratorCoreOverride.spec.ts new file mode 100644 index 0000000000..683d4f3542 --- /dev/null +++ b/packages/typespec-ts/test/azureIntegration/azureClientGeneratorCoreOverride.spec.ts @@ -0,0 +1,72 @@ +import { assert } from "chai"; +import OverrideClientFactory, { + OverrideClient +} from "./generated/azure/client-generator-core/override/src/index.js"; + +describe("Azure Client Generator Core Override", () => { + let client: OverrideClient; + + beforeEach(() => { + client = OverrideClientFactory({ + allowInsecureConnection: true + }); + }); + + it("should reorder parameters correctly", async () => { + // Test parameter reordering with @override decorator + // Expected path: /azure/client-generator-core/override/reorder/{param2}/{param1} + // Where param1="param1" and param2="param2" + const result = await client + .path( + "/azure/client-generator-core/override/reorder/{param2}/{param1}", + "param2", // param2 value + "param1" // param1 value + ) + .get(); + assert.strictEqual(result.status, "204"); + }); + + it("should group parameters correctly", async () => { + // Test parameter grouping with @override decorator + // Verifies that parameters are grouped correctly into GroupParametersOptions + // Expected query parameters: param1="param1", param2="param2" + const result = await client + .path("/azure/client-generator-core/override/group") + .get({ + queryParameters: { + param1: "param1", + param2: "param2" + } + }); + assert.strictEqual(result.status, "204"); + }); + + it("should require optional parameter", async () => { + // Test parameter requirement with @override decorator + // Verifies that optional parameters can be made required via @override + const result = await client + .path( + "/azure/client-generator-core/override/require-optional/{param1}/{param2}", + "param1", // param1 value + "param2" // param2 value + ) + .get(); + assert.strictEqual(result.status, "204"); + }); + + it("should remove optional parameter", async () => { + // Test parameter requirement with @override decorator + // Verifies that optional parameters can be removed via @override + const result = await client + .path( + "/azure/client-generator-core/override/remove-optional/{param1}", + "param1" // param1 value + ) + .get({ + queryParameters: { + param2: "param2" + } + }); + assert.strictEqual(result.status, "204"); + }); +}); diff --git a/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/.gitignore b/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/.gitignore new file mode 100644 index 0000000000..39220655cc --- /dev/null +++ b/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/.gitignore @@ -0,0 +1,6 @@ +/** +!/src +/src/** +!/src/index.d.ts +!/.gitignore +!/tspconfig.yaml diff --git a/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/src/index.d.ts b/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/src/index.d.ts new file mode 100644 index 0000000000..0df9dce879 --- /dev/null +++ b/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/src/index.d.ts @@ -0,0 +1,91 @@ +import type { Client } from '@azure-rest/core-client'; +import type { ClientOptions } from '@azure-rest/core-client'; +import type { HttpResponse } from '@azure-rest/core-client'; +import type { RawHttpHeadersInput } from '@azure/core-rest-pipeline'; +import type { RequestParameters } from '@azure-rest/core-client'; +import type { StreamableMethod } from '@azure-rest/core-client'; + +declare function createClient(options?: OverrideClientOptions): OverrideClient; +export default createClient; + +export declare interface Group { + get(options: GroupParameters): StreamableMethod; +} + +export declare interface Group204Response extends HttpResponse { + status: "204"; +} + +export declare type GroupParameters = GroupQueryParam & RequestParameters; + +export declare interface GroupQueryParam { + queryParameters: GroupQueryParamProperties; +} + +export declare interface GroupQueryParamProperties { + param1: string; + param2: string; +} + +export declare type OverrideClient = Client & { + path: Routes; +}; + +export declare interface OverrideClientOptions extends ClientOptions { +} + +export declare interface RemoveOptional { + get(options?: RemoveOptionalParameters): StreamableMethod; +} + +export declare interface RemoveOptional204Response extends HttpResponse { + status: "204"; +} + +export declare interface RemoveOptionalHeaderParam { + headers?: RawHttpHeadersInput & RemoveOptionalHeaders; +} + +export declare interface RemoveOptionalHeaders { + param4?: string; +} + +export declare type RemoveOptionalParameters = RemoveOptionalQueryParam & RemoveOptionalHeaderParam & RequestParameters; + +export declare interface RemoveOptionalQueryParam { + queryParameters?: RemoveOptionalQueryParamProperties; +} + +export declare interface RemoveOptionalQueryParamProperties { + param2?: string; + param3?: string; +} + +export declare interface Reorder { + get(options?: ReorderParameters): StreamableMethod; +} + +export declare interface Reorder204Response extends HttpResponse { + status: "204"; +} + +export declare type ReorderParameters = RequestParameters; + +export declare interface RequireOptional { + get(options?: RequireOptionalParameters): StreamableMethod; +} + +export declare interface RequireOptional204Response extends HttpResponse { + status: "204"; +} + +export declare type RequireOptionalParameters = RequestParameters; + +export declare interface Routes { + (path: "/azure/client-generator-core/override/reorder/{param2}/{param1}", param2: string, param1: string): Reorder; + (path: "/azure/client-generator-core/override/group"): Group; + (path: "/azure/client-generator-core/override/require-optional/{param1}/{param2}", param1: string, param2: string): RequireOptional; + (path: "/azure/client-generator-core/override/remove-optional/{param1}", param1: string): RemoveOptional; +} + +export { } diff --git a/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/tspconfig.yaml b/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/tspconfig.yaml new file mode 100644 index 0000000000..e59a4161bc --- /dev/null +++ b/packages/typespec-ts/test/azureIntegration/generated/azure/client-generator-core/override/tspconfig.yaml @@ -0,0 +1,12 @@ +emit: + - "@azure-tools/typespec-ts" +options: + "@azure-tools/typespec-ts": + emitter-output-dir: "{project-root}" + generate-test: false + add-credentials: false + flavor: azure + azure-sdk-for-js: false + is-typespec-test: true + package-details: + name: "@msinternal/override" diff --git a/packages/typespec-ts/test/azureModularIntegration/azureClientGeneratorCoreOverride.spec.ts b/packages/typespec-ts/test/azureModularIntegration/azureClientGeneratorCoreOverride.spec.ts new file mode 100644 index 0000000000..b068204325 --- /dev/null +++ b/packages/typespec-ts/test/azureModularIntegration/azureClientGeneratorCoreOverride.spec.ts @@ -0,0 +1,45 @@ +import { OverrideClient } from "./generated/azure/client-generator-core/override/src/index.js"; + +describe("Azure ClientGeneratorCore Override Client", () => { + let client: OverrideClient; + + beforeEach(() => { + client = new OverrideClient({ + endpoint: "http://localhost:3002", + allowInsecureConnection: true + }); + }); + + it("should reorder parameters correctly", async () => { + // Test parameter reordering with @override decorator + // Verifies that parameters are reordered correctly in client method signature + // Expected path: /azure/client-generator-core/override/reorder/{param2}/{param1} + // Where param1="param1" and param2="param2" + await client.reorderParameters.reorder("param1", "param2"); + }); + + it("should group parameters correctly", async () => { + // Test parameter grouping with @override decorator + // Verifies that parameters are grouped correctly into GroupParametersOptions + // Expected query parameters: param1="param1", param2="param2" + const options = { + param1: "param1", + param2: "param2" + }; + await client.groupParameters.group(options.param1, options.param2); + }); + + it("should require optional parameter correctly", async () => { + // Test parameter requirement with @override decorator + // Verifies that optional parameters can be made required via @override + await client.requireOptionalParameter.requireOptional("param1", "param2"); + }); + + it("should remove optional parameter correctly", async () => { + // Test parameter removal with @override decorator + // Verifies that optional parameters can be removed via @override + await client.removeOptionalParameter.removeOptional("param1", { + param2: "param2" + }); + }); +}); diff --git a/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/.gitignore b/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/.gitignore new file mode 100644 index 0000000000..39220655cc --- /dev/null +++ b/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/.gitignore @@ -0,0 +1,6 @@ +/** +!/src +/src/** +!/src/index.d.ts +!/.gitignore +!/tspconfig.yaml diff --git a/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/src/index.d.ts b/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/src/index.d.ts new file mode 100644 index 0000000000..9434bebb4c --- /dev/null +++ b/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/src/index.d.ts @@ -0,0 +1,47 @@ +import { ClientOptions } from '@azure-rest/core-client'; +import { OperationOptions } from '@azure-rest/core-client'; +import { Pipeline } from '@azure/core-rest-pipeline'; + +export declare interface GroupParametersGroupOptionalParams extends OperationOptions { +} + +export declare interface GroupParametersOperations { + group: (param1: string, param2: string, options?: GroupParametersGroupOptionalParams) => Promise; +} + +export declare class OverrideClient { + private _client; + readonly pipeline: Pipeline; + constructor(options?: OverrideClientOptionalParams); + readonly removeOptionalParameter: RemoveOptionalParameterOperations; + readonly requireOptionalParameter: RequireOptionalParameterOperations; + readonly groupParameters: GroupParametersOperations; + readonly reorderParameters: ReorderParametersOperations; +} + +export declare interface OverrideClientOptionalParams extends ClientOptions { +} + +export declare interface RemoveOptionalParameterOperations { + removeOptional: (param1: string, options?: RemoveOptionalParameterRemoveOptionalOptionalParams) => Promise; +} + +export declare interface RemoveOptionalParameterRemoveOptionalOptionalParams extends OperationOptions { + param2?: string; +} + +export declare interface ReorderParametersOperations { + reorder: (param1: string, param2: string, options?: ReorderParametersReorderOptionalParams) => Promise; +} + +export declare interface ReorderParametersReorderOptionalParams extends OperationOptions { +} + +export declare interface RequireOptionalParameterOperations { + requireOptional: (param1: string, param2: string, options?: RequireOptionalParameterRequireOptionalOptionalParams) => Promise; +} + +export declare interface RequireOptionalParameterRequireOptionalOptionalParams extends OperationOptions { +} + +export { } diff --git a/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/tspconfig.yaml b/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/tspconfig.yaml new file mode 100644 index 0000000000..43fff85877 --- /dev/null +++ b/packages/typespec-ts/test/azureModularIntegration/generated/azure/client-generator-core/override/tspconfig.yaml @@ -0,0 +1,11 @@ +emit: + - "@azure-tools/typespec-ts" +options: + "@azure-tools/typespec-ts": + emitter-output-dir: "{project-root}" + add-credentials: false + azure-sdk-for-js: false + is-modular-library: true + package-details: + name: "@azure/client-generator-core-override" + version: "1.0.0" diff --git a/packages/typespec-ts/test/commands/cadl-ranch-list.js b/packages/typespec-ts/test/commands/cadl-ranch-list.js index c07ec48dfe..2c6bf59598 100644 --- a/packages/typespec-ts/test/commands/cadl-ranch-list.js +++ b/packages/typespec-ts/test/commands/cadl-ranch-list.js @@ -335,6 +335,10 @@ export const azureRlcTsps = [ { outputPath: "azure/client-generator-core/client-location", inputPath: "azure/client-generator-core/client-location" + }, + { + outputPath: "azure/client-generator-core/override", + inputPath: "azure/client-generator-core/override" } ]; @@ -863,6 +867,10 @@ export const azureModularTsps = [ { outputPath: "azure/client-generator-core/hierarchy-building", inputPath: "azure/client-generator-core/hierarchy-building" + }, + { + outputPath: "azure/client-generator-core/override", + inputPath: "azure/client-generator-core/override" } // skip due to issue https://github.com/Azure/autorest.typescript/issues/3494 // { diff --git a/packages/typespec-ts/test/modularUnit/scenarios/operations/override.md b/packages/typespec-ts/test/modularUnit/scenarios/operations/override.md index 5168c9241c..0516ba4e25 100644 --- a/packages/typespec-ts/test/modularUnit/scenarios/operations/override.md +++ b/packages/typespec-ts/test/modularUnit/scenarios/operations/override.md @@ -102,3 +102,252 @@ export async function getSecretOriginal( return _getSecretOriginalDeserialize(result); } ``` + +# skip: Should handle parameter grouping when using @@override + +Tests that parameters are correctly grouped into options model when using @@override directive. + +## TypeSpec + +```tsp +import "@typespec/http"; +import "@azure-tools/typespec-client-generator-core"; +using TypeSpec.Http; +using Azure.ClientGenerator.Core; + +@service(#{ + title: "Override Service" +}) +namespace Override; + +// Original operation with separate query parameters +@route("/group") +@get +op groupOriginal( + @query param1: string, + @query param2: string, +): void; + +// Override model to group parameters +model GroupParametersOptions { + @query param1: string; + @query param2: string; +} + +// Override operation with grouped parameters +op groupCustomized( + options: GroupParametersOptions, +): void; + +@@override(Override.groupOriginal, Override.groupCustomized); +``` + +The config would be like: + +```yaml +needTCGC: true +needAzureCore: true +withRawContent: true +``` + +## Models + +```ts models +/** model interface GroupParametersOptions */ +export interface GroupParametersOptions { + param1: string; + param2: string; +} + +export function groupParametersOptionsSerializer( + item: GroupParametersOptions, +): any { + return { param1: item["param1"], param2: item["param2"] }; +} +``` + +## Models with Options + +The options interface should be correctly generated: + +```ts models:withOptions +import { OperationOptions } from "@azure-rest/core-client"; + +/** Optional parameters. */ +export interface GroupOriginalOptionalParams extends OperationOptions {} +``` + +## Operations + +```ts operations +import { OverrideContext as Client } from "./index.js"; +import { GroupParametersOptions } from "../models/models.js"; +import { expandUrlTemplate } from "../static-helpers/urlTemplate.js"; +import { GroupOriginalOptionalParams } from "./options.js"; +import { + StreamableMethod, + PathUncheckedResponse, + createRestError, + operationOptionsToRequestParameters, +} from "@azure-rest/core-client"; + +export function _groupOriginalSend( + context: Client, + options: GroupParametersOptions, + optionalParams: GroupOriginalOptionalParams = { requestOptions: {} }, +): StreamableMethod { + const path = expandUrlTemplate( + "/group{?param1,param2}", + { + param1: options.param1, + param2: options.param2, + }, + { + allowReserved: optionalParams?.requestOptions?.skipUrlEncoding, + }, + ); + return context + .path(path) + .get({ ...operationOptionsToRequestParameters(optionalParams) }); +} + +export async function _groupOriginalDeserialize( + result: PathUncheckedResponse, +): Promise { + const expectedStatuses = ["204"]; + if (!expectedStatuses.includes(result.status)) { + throw createRestError(result); + } + + return; +} + +export async function groupOriginal( + context: Client, + options: GroupParametersOptions, + optionalParams: GroupOriginalOptionalParams = { requestOptions: {} }, +): Promise { + const result = await _groupOriginalSend(context, options, optionalParams); + return _groupOriginalDeserialize(result); +} +``` + +# Should handle parameter removal when using @@override + +Tests that optional parameters are correctly handled when removed using @@override directive. + +## TypeSpec + +```tsp +import "@typespec/http"; +import "@azure-tools/typespec-client-generator-core"; +using TypeSpec.Http; +using Azure.ClientGenerator.Core; + +@service(#{ + title: "Override Service" +}) +namespace Override; + +// Original operation with multiple optional parameters +@route("/remove-optional/{param1}") +@get +op removeOptionalOriginal( + @path param1: string, + @query param2?: string, + @query param3?: string, + @header param4?: string, + @header param5?: string, +): void; + +// Override operation removing some optional parameters +op removeOptionalCustomized( + @path param1: string, + @query param2?: string, + @header param4?: string, +): void; + +@@override(Override.removeOptionalOriginal, Override.removeOptionalCustomized); +``` + +The config would be like: + +```yaml +needTCGC: true +needAzureCore: true +withRawContent: true +``` + +## Models with Options + +The options interface should only include parameters that exist in the override operation: + +```ts models:withOptions +import { OperationOptions } from "@azure-rest/core-client"; + +/** Optional parameters. */ +export interface RemoveOptionalOriginalOptionalParams extends OperationOptions { + param2?: string; + param4?: string; +} +``` + +## Operations + +```ts operations +import { OverrideContext as Client } from "./index.js"; +import { expandUrlTemplate } from "../static-helpers/urlTemplate.js"; +import { RemoveOptionalOriginalOptionalParams } from "./options.js"; +import { + StreamableMethod, + PathUncheckedResponse, + createRestError, + operationOptionsToRequestParameters, +} from "@azure-rest/core-client"; + +export function _removeOptionalOriginalSend( + context: Client, + param1: string, + options: RemoveOptionalOriginalOptionalParams = { requestOptions: {} }, +): StreamableMethod { + const path = expandUrlTemplate( + "/remove-optional/{param1}{?param2,param3}", + { + param1: param1, + param2: options?.param2, + }, + { + allowReserved: options?.requestOptions?.skipUrlEncoding, + }, + ); + return context + .path(path) + .get({ + ...operationOptionsToRequestParameters(options), + headers: { + ...(options?.param4 !== undefined ? { param4: options?.param4 } : {}), + ...options.requestOptions?.headers, + }, + }); +} + +export async function _removeOptionalOriginalDeserialize( + result: PathUncheckedResponse, +): Promise { + const expectedStatuses = ["204"]; + if (!expectedStatuses.includes(result.status)) { + throw createRestError(result); + } + + return; +} + +export async function removeOptionalOriginal( + context: Client, + param1: string, + options: RemoveOptionalOriginalOptionalParams = { requestOptions: {} }, +): Promise { + const result = await _removeOptionalOriginalSend(context, param1, options); + return _removeOptionalOriginalDeserialize(result); +} +```