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