From 7d39ff51676801d5db113d78e3214b02e7a77b09 Mon Sep 17 00:00:00 2001 From: "Ziheng Zhou(MSFT)" Date: Thu, 16 Nov 2023 12:59:42 +0800 Subject: [PATCH] Add modular coverage cases for azure-core-traits in cadl-ranch (#2122) * add coverage for unions and two more. * remove unions * remove projection --- .../test/commands/cadl-ranch-list.ts | 4 + .../azureCoreTraits.spec.ts | 53 ++++++++ .../azure/core-traits/.eslintrc.json | 11 ++ .../generated/azure/core-traits/README.md | 56 ++++++++ .../azure/core-traits/api-extractor.json | 18 +++ .../generated/azure/core-traits/package.json | 96 ++++++++++++++ .../azure/core-traits/rollup.config.js | 118 +++++++++++++++++ .../azure/core-traits/src/TraitsClient.ts | 45 +++++++ .../core-traits/src/api/TraitsContext.ts | 16 +++ .../azure/core-traits/src/api/index.ts | 9 ++ .../azure/core-traits/src/api/operations.ts | 125 ++++++++++++++++++ .../generated/azure/core-traits/src/index.ts | 11 ++ .../generated/azure/core-traits/src/logger.ts | 5 + .../azure/core-traits/src/models/index.ts | 5 + .../azure/core-traits/src/models/models.ts | 22 +++ .../azure/core-traits/src/models/options.ts | 24 ++++ .../core-traits/src/rest/clientDefinitions.ts | 44 ++++++ .../azure/core-traits/src/rest/index.ts | 14 ++ .../core-traits/src/rest/isUnexpected.ts | 110 +++++++++++++++ .../azure/core-traits/src/rest/models.ts | 8 ++ .../core-traits/src/rest/outputModels.ts | 31 +++++ .../azure/core-traits/src/rest/parameters.ts | 46 +++++++ .../azure/core-traits/src/rest/responses.ts | 55 ++++++++ .../core-traits/src/rest/traitsClient.ts | 35 +++++ .../generated/azure/core-traits/tsconfig.json | 27 ++++ .../azure/core-traits/tspconfig.yaml | 14 ++ 26 files changed, 1002 insertions(+) create mode 100644 packages/typespec-ts/test/modularIntegration/azureCoreTraits.spec.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/.eslintrc.json create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/README.md create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/api-extractor.json create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/package.json create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/rollup.config.js create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/TraitsClient.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/TraitsContext.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/operations.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/logger.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/models.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/options.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/clientDefinitions.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/index.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/isUnexpected.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/models.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/outputModels.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/parameters.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/responses.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/traitsClient.ts create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/tsconfig.json create mode 100644 packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/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 09070ddf27..7800d3c156 100644 --- a/packages/typespec-ts/test/commands/cadl-ranch-list.ts +++ b/packages/typespec-ts/test/commands/cadl-ranch-list.ts @@ -270,6 +270,10 @@ export const modularTsps: TypeSpecRanchConfig[] = [ { outputPath: "headers/repeatability", inputPath: "special-headers/repeatability" + }, + { + outputPath: "azure/core-traits", + inputPath: "azure/core/traits" } ]; diff --git a/packages/typespec-ts/test/modularIntegration/azureCoreTraits.spec.ts b/packages/typespec-ts/test/modularIntegration/azureCoreTraits.spec.ts new file mode 100644 index 0000000000..c194c3e350 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/azureCoreTraits.spec.ts @@ -0,0 +1,53 @@ +import { TraitsClient } from "./generated/azure/core-traits/src/index.js"; +import { assert } from "chai"; + +describe("Traits Client", () => { + let client: TraitsClient; + + beforeEach(() => { + client = new TraitsClient({ + allowInsecureConnection: true + }); + }); + + it("client smoke test", async () => { + try { + const result = await client.smokeTest(1, "123", { + ifNoneMatch: '"invalid"', + ifMatch: '"valid"', + ifUnmodifiedSince: new Date("Fri, 26 Aug 2022 14:38:00 GMT"), + ifModifiedSince: new Date("Thu, 26 Aug 2021 14:38:00 GMT") + }); + assert.isNotNull(result); + assert.strictEqual( + JSON.stringify(result), + JSON.stringify({ + id: 1, + name: "Madge" + }) + ); + } catch (err) { + assert.fail(err as string); + } + }); + + it("client repeatable action", async () => { + try { + const result = await client.repeatableAction( + 1, + { userActionValue: "test" }, + { + repeatabilityRequestId: "86aede1f-96fa-4e7f-b1e1-bf8a947cb804", + repeatabilityFirstSent: new Date("Wed, 15 Nov 2023 15:38:00 GMT") + } + ); + assert.isNotNull(result); + assert.strictEqual( + JSON.stringify(result), + JSON.stringify({ userActionResult: "test" }) + ); + } catch (err) { + assert.fail(err as string); + } + }); +}); diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/.eslintrc.json b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/.eslintrc.json new file mode 100644 index 0000000000..619797ac39 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/.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-traits/README.md b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/README.md new file mode 100644 index 0000000000..503f6ab910 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/README.md @@ -0,0 +1,56 @@ +# Traits REST client library for JavaScript + +Illustrates Azure Core operation customizations by traits + +**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-traits) + +## 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-traits` package + +Install the Traits REST client REST client library for JavaScript with `npm`: + +```bash +npm install @msinternal/azure-core-traits +``` + +### Create and authenticate a `TraitsClient` + +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-traits/api-extractor.json b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/api-extractor.json new file mode 100644 index 0000000000..e8c6c04295 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/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-traits.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-traits/package.json b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/package.json new file mode 100644 index 0000000000..a0a51122e5 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/package.json @@ -0,0 +1,96 @@ +{ + "name": "@msinternal/azure-core-traits", + "sdk-type": "client", + "author": "Microsoft Corporation", + "version": "1.0.0-beta.1", + "description": "A generated SDK for Traits.", + "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-traits.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-traits.d.ts", + "README.md", + "LICENSE", + "review/*" + ], + "engines": { "node": ">=18.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 --glob 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-util": "^1.4.0" + }, + "devDependencies": { + "@microsoft/api-extractor": "^7.31.1", + "autorest": "latest", + "@types/node": "^18.0.0", + "dotenv": "^16.0.0", + "eslint": "^8.0.0", + "mkdirp": "^2.1.2", + "prettier": "^2.5.1", + "rimraf": "^5.0.0", + "source-map-support": "^0.5.9", + "typescript": "~5.2.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-traits/rollup.config.js b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/rollup.config.js new file mode 100644 index 0000000000..61251d7a8d --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/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-traits/src/TraitsClient.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/TraitsClient.ts new file mode 100644 index 0000000000..f6ac019863 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/TraitsClient.ts @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { Pipeline } from "@azure/core-rest-pipeline"; +import { User, UserActionParam, UserActionResponse } from "./models/models.js"; +import { SmokeTestOptions, RepeatableActionOptions } from "./models/options.js"; +import { + smokeTest, + repeatableAction, + createTraits, + TraitsClientOptions, + TraitsContext, +} from "./api/index.js"; + +export { TraitsClientOptions } from "./api/TraitsContext.js"; + +export class TraitsClient { + private _client: TraitsContext; + /** The pipeline used by this client to make requests */ + public readonly pipeline: Pipeline; + + /** Illustrates Azure Core operation customizations by traits */ + constructor(options: TraitsClientOptions = {}) { + this._client = createTraits(options); + this.pipeline = this._client.pipeline; + } + + /** Get a resource, sending and receiving headers. */ + smokeTest( + id: number, + foo: string, + options: SmokeTestOptions = { requestOptions: {} } + ): Promise { + return smokeTest(this._client, id, foo, options); + } + + /** Test for repeatable requests */ + repeatableAction( + id: number, + body: UserActionParam, + options: RepeatableActionOptions = { requestOptions: {} } + ): Promise { + return repeatableAction(this._client, id, body, options); + } +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/TraitsContext.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/TraitsContext.ts new file mode 100644 index 0000000000..d65c51e918 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/TraitsContext.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { ClientOptions } from "@azure-rest/core-client"; +import { TraitsContext } from "../rest/index.js"; +import getClient from "../rest/index.js"; + +export interface TraitsClientOptions extends ClientOptions {} + +export { TraitsContext } from "../rest/index.js"; + +/** Illustrates Azure Core operation customizations by traits */ +export function createTraits(options: TraitsClientOptions = {}): TraitsContext { + const clientContext = getClient(options); + return clientContext; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/index.ts new file mode 100644 index 0000000000..1ad3884e73 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/index.ts @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { smokeTest, repeatableAction } from "./operations.js"; +export { + createTraits, + TraitsClientOptions, + TraitsContext, +} from "./TraitsContext.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/operations.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/operations.ts new file mode 100644 index 0000000000..a889ad738c --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/api/operations.ts @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { User, UserActionParam, UserActionResponse } from "../models/models.js"; +import { + isUnexpected, + RepeatableAction200Response, + RepeatableActionDefaultResponse, + SmokeTest200Response, + SmokeTestDefaultResponse, + TraitsContext as Client, +} from "../rest/index.js"; +import { + StreamableMethod, + operationOptionsToRequestParameters, +} from "@azure-rest/core-client"; +import { + SmokeTestOptions, + RepeatableActionOptions, +} from "../models/options.js"; + +export function _smokeTestSend( + context: Client, + id: number, + foo: string, + options: SmokeTestOptions = { requestOptions: {} } +): StreamableMethod { + return context + .path("/azure/core/traits/user/{id}", id) + .get({ + ...operationOptionsToRequestParameters(options), + headers: { + foo: foo, + ...(options?.ifMatch !== undefined + ? { "If-Match": options?.ifMatch } + : {}), + ...(options?.ifNoneMatch !== undefined + ? { "If-None-Match": options?.ifNoneMatch } + : {}), + ...(options?.ifUnmodifiedSince !== undefined + ? { "If-Unmodified-Since": options?.ifUnmodifiedSince?.toUTCString() } + : {}), + ...(options?.ifModifiedSince !== undefined + ? { "If-Modified-Since": options?.ifModifiedSince?.toUTCString() } + : {}), + ...(options?.clientRequestId !== undefined + ? { "x-ms-client-request-id": options?.clientRequestId } + : {}), + }, + }); +} + +export async function _smokeTestDeserialize( + result: SmokeTest200Response | SmokeTestDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + id: result.body["id"], + name: result.body["name"], + }; +} + +/** Get a resource, sending and receiving headers. */ +export async function smokeTest( + context: Client, + id: number, + foo: string, + options: SmokeTestOptions = { requestOptions: {} } +): Promise { + const result = await _smokeTestSend(context, id, foo, options); + return _smokeTestDeserialize(result); +} + +export function _repeatableActionSend( + context: Client, + id: number, + body: UserActionParam, + options: RepeatableActionOptions = { requestOptions: {} } +): StreamableMethod< + RepeatableAction200Response | RepeatableActionDefaultResponse +> { + return context + .path("/azure/core/traits/user/{id}:repeatableAction", id) + .post({ + ...operationOptionsToRequestParameters(options), + headers: { + ...(options?.repeatabilityRequestId !== undefined + ? { "Repeatability-Request-ID": options?.repeatabilityRequestId } + : {}), + ...(options?.repeatabilityFirstSent !== undefined + ? { + "Repeatability-First-Sent": + options?.repeatabilityFirstSent?.toUTCString(), + } + : {}), + }, + body: { userActionValue: body["userActionValue"] }, + }); +} + +export async function _repeatableActionDeserialize( + result: RepeatableAction200Response | RepeatableActionDefaultResponse +): Promise { + if (isUnexpected(result)) { + throw result.body; + } + + return { + userActionResult: result.body["userActionResult"], + }; +} + +/** Test for repeatable requests */ +export async function repeatableAction( + context: Client, + id: number, + body: UserActionParam, + options: RepeatableActionOptions = { requestOptions: {} } +): Promise { + const result = await _repeatableActionSend(context, id, body, options); + return _repeatableActionDeserialize(result); +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/index.ts new file mode 100644 index 0000000000..23cc502f1e --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/index.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { TraitsClient, TraitsClientOptions } from "./TraitsClient.js"; +export { + User, + UserActionParam, + UserActionResponse, + SmokeTestOptions, + RepeatableActionOptions, +} from "./models/index.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/logger.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/logger.ts new file mode 100644 index 0000000000..368f69c470 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/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-traits"); diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/index.ts new file mode 100644 index 0000000000..4273cfb917 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +export { User, UserActionParam, UserActionResponse } from "./models.js"; +export { SmokeTestOptions, RepeatableActionOptions } from "./options.js"; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/models.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/models.ts new file mode 100644 index 0000000000..aa60809780 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/models.ts @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** Sample Model */ +export interface User { + /** The user's id. */ + readonly id: number; + /** The user's name. */ + name?: string; +} + +/** User action param */ +export interface UserActionParam { + /** User action value. */ + userActionValue: string; +} + +/** User action response */ +export interface UserActionResponse { + /** User action result. */ + userActionResult: string; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/options.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/options.ts new file mode 100644 index 0000000000..1bcba56025 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/models/options.ts @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { OperationOptions } from "@azure-rest/core-client"; + +export interface SmokeTestOptions extends OperationOptions { + /** The request should only proceed if an entity matches this string. */ + ifMatch?: string; + /** The request should only proceed if no entity matches this string. */ + ifNoneMatch?: string; + /** The request should only proceed if the entity was not modified after this time. */ + ifUnmodifiedSince?: Date; + /** The request should only proceed if the entity was modified after this time. */ + ifModifiedSince?: Date; + /** An opaque, globally-unique, client-generated string identifier for the request. */ + clientRequestId?: string; +} + +export interface RepeatableActionOptions extends OperationOptions { + /** An opaque, globally-unique, client-generated string identifier for the request. */ + repeatabilityRequestId?: string; + /** Specifies the date and time at which the request was first created. */ + repeatabilityFirstSent?: Date; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/clientDefinitions.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/clientDefinitions.ts new file mode 100644 index 0000000000..c762a96e1b --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/clientDefinitions.ts @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + SmokeTestParameters, + RepeatableActionParameters, +} from "./parameters.js"; +import { + SmokeTest200Response, + SmokeTestDefaultResponse, + RepeatableAction200Response, + RepeatableActionDefaultResponse, +} from "./responses.js"; +import { Client, StreamableMethod } from "@azure-rest/core-client"; + +export interface SmokeTest { + /** Get a resource, sending and receiving headers. */ + get( + options: SmokeTestParameters + ): StreamableMethod; +} + +export interface RepeatableAction { + /** Test for repeatable requests */ + post( + options?: RepeatableActionParameters + ): StreamableMethod< + RepeatableAction200Response | RepeatableActionDefaultResponse + >; +} + +export interface Routes { + /** Resource for '/azure/core/traits/user/\{id\}' has methods for the following verbs: get */ + (path: "/azure/core/traits/user/{id}", id: number): SmokeTest; + /** Resource for '/azure/core/traits/user/\{id\}:repeatableAction' has methods for the following verbs: post */ + ( + path: "/azure/core/traits/user/{id}:repeatableAction", + id: number + ): RepeatableAction; +} + +export type TraitsContext = Client & { + path: Routes; +}; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/index.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/index.ts new file mode 100644 index 0000000000..f1e745822b --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/index.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import TraitsClient from "./traitsClient.js"; + +export * from "./traitsClient.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 default TraitsClient; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/isUnexpected.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/isUnexpected.ts new file mode 100644 index 0000000000..20332a5521 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/isUnexpected.ts @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + SmokeTest200Response, + SmokeTestDefaultResponse, + RepeatableAction200Response, + RepeatableActionDefaultResponse, +} from "./responses.js"; + +const responseMap: Record = { + "GET /azure/core/traits/user/{id}": ["200"], + "POST /azure/core/traits/user/{id}:repeatableAction": ["200"], +}; + +export function isUnexpected( + response: SmokeTest200Response | SmokeTestDefaultResponse +): response is SmokeTestDefaultResponse; +export function isUnexpected( + response: RepeatableAction200Response | RepeatableActionDefaultResponse +): response is RepeatableActionDefaultResponse; +export function isUnexpected( + response: + | SmokeTest200Response + | SmokeTestDefaultResponse + | RepeatableAction200Response + | RepeatableActionDefaultResponse +): response is SmokeTestDefaultResponse | RepeatableActionDefaultResponse { + 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-traits/src/rest/models.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/models.ts new file mode 100644 index 0000000000..54fed3a1ae --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/models.ts @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** User action param */ +export interface UserActionParam { + /** User action value. */ + userActionValue: string; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/outputModels.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/outputModels.ts new file mode 100644 index 0000000000..06eeeb6fab --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/outputModels.ts @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** Provides the 'If-*' headers to enable conditional (cached) responses */ +export interface ConditionalRequestHeadersOutput {} + +/** Provides the 'ETag' header to enable conditional (cached) requests */ +export interface EtagResponseEnvelopeOutput {} + +/** Provides the 'x-ms-client-request-id' header to enable request correlation in requests and responses. */ +export interface ClientRequestIdHeaderOutput {} + +/** Sample Model */ +export interface UserOutput { + /** The user's id. */ + readonly id: number; + /** The user's name. */ + name?: string; +} + +/** Provides the 'Repeatability-*' headers to enable repeatable requests. */ +export interface RepeatabilityRequestHeadersOutput {} + +/** Provides the 'Repeatability-*' headers to enable repeatable requests. */ +export interface RepeatabilityResponseHeadersOutput {} + +/** User action response */ +export interface UserActionResponseOutput { + /** User action result. */ + userActionResult: string; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/parameters.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/parameters.ts new file mode 100644 index 0000000000..1c1dd5646c --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/parameters.ts @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { RawHttpHeadersInput } from "@azure/core-rest-pipeline"; +import { RequestParameters } from "@azure-rest/core-client"; +import { UserActionParam } from "./models.js"; + +export interface SmokeTestHeaders { + /** header in request */ + foo: string; + /** The request should only proceed if an entity matches this string. */ + "If-Match"?: string; + /** The request should only proceed if no entity matches this string. */ + "If-None-Match"?: string; + /** The request should only proceed if the entity was not modified after this time. */ + "If-Unmodified-Since"?: string; + /** The request should only proceed if the entity was modified after this time. */ + "If-Modified-Since"?: string; + /** An opaque, globally-unique, client-generated string identifier for the request. */ + "x-ms-client-request-id"?: string; +} + +export interface SmokeTestHeaderParam { + headers: RawHttpHeadersInput & SmokeTestHeaders; +} + +export type SmokeTestParameters = SmokeTestHeaderParam & RequestParameters; + +export interface RepeatableActionHeaders { + /** An opaque, globally-unique, client-generated string identifier for the request. */ + "Repeatability-Request-ID"?: string; + /** Specifies the date and time at which the request was first created. */ + "Repeatability-First-Sent"?: string; +} + +export interface RepeatableActionBodyParam { + body?: UserActionParam; +} + +export interface RepeatableActionHeaderParam { + headers?: RawHttpHeadersInput & RepeatableActionHeaders; +} + +export type RepeatableActionParameters = RepeatableActionHeaderParam & + RepeatableActionBodyParam & + RequestParameters; diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/responses.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/responses.ts new file mode 100644 index 0000000000..f17960afaf --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/responses.ts @@ -0,0 +1,55 @@ +// 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, UserActionResponseOutput } from "./outputModels.js"; + +export interface SmokeTest200Headers { + bar: string; + /** The entity tag for the response. */ + etag?: string; + /** An opaque, globally-unique, client-generated string identifier for the request. */ + "x-ms-client-request-id"?: string; +} + +/** The request has succeeded. */ +export interface SmokeTest200Response extends HttpResponse { + status: "200"; + body: UserOutput; + headers: RawHttpHeaders & SmokeTest200Headers; +} + +export interface SmokeTestDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface SmokeTestDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & SmokeTestDefaultHeaders; +} + +export interface RepeatableAction200Headers { + /** Indicates whether the repeatable request was accepted or rejected. */ + "repeatability-result"?: "accepted" | "rejected"; +} + +/** The request has succeeded. */ +export interface RepeatableAction200Response extends HttpResponse { + status: "200"; + body: UserActionResponseOutput; + headers: RawHttpHeaders & RepeatableAction200Headers; +} + +export interface RepeatableActionDefaultHeaders { + /** String error code indicating what went wrong. */ + "x-ms-error-code"?: string; +} + +export interface RepeatableActionDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponse; + headers: RawHttpHeaders & RepeatableActionDefaultHeaders; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/traitsClient.ts b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/traitsClient.ts new file mode 100644 index 0000000000..561cd07324 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/src/rest/traitsClient.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 { TraitsContext } from "./clientDefinitions.js"; + +/** + * Initialize a new instance of `TraitsContext` + * @param options - the parameter for all optional parameters + */ +export default function createClient( + options: ClientOptions = {} +): TraitsContext { + const baseUrl = options.baseUrl ?? `http://localhost:3000`; + options.apiVersion = options.apiVersion ?? "2022-12-01-preview"; + const userAgentInfo = `azsdk-js-azure-core-traits-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 TraitsContext; + + return client; +} diff --git a/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/tsconfig.json b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/tsconfig.json new file mode 100644 index 0000000000..d8b77d0227 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/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-traits/tspconfig.yaml b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/tspconfig.yaml new file mode 100644 index 0000000000..8978c49dd0 --- /dev/null +++ b/packages/typespec-ts/test/modularIntegration/generated/azure/core-traits/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 + isTypeSpecTest: true + isModularLibrary: true + hierarchyClient: false + packageDetails: + name: "@msinternal/azure-core-traits"