diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/.eslintrc.json b/packages/cadl-rlc-test/test/customWrapper/cadl-output/.eslintrc.json new file mode 100644 index 0000000000..619797ac39 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/.eslintrc.json @@ -0,0 +1,11 @@ +{ + "plugins": ["@azure/azure-sdk"], + "extends": ["plugin:@azure/azure-sdk/azure-sdk-base"], + "rules": { + "@azure/azure-sdk/ts-modules-only-named": "warn", + "@azure/azure-sdk/ts-apiextractor-json-types": "warn", + "@azure/azure-sdk/ts-package-json-types": "warn", + "@azure/azure-sdk/ts-package-json-engine-is-present": "warn", + "tsdoc/syntax": "warn" + } +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/README.md b/packages/cadl-rlc-test/test/customWrapper/cadl-output/README.md new file mode 100644 index 0000000000..d1b1e8941d --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/README.md @@ -0,0 +1,56 @@ +# Microsoft Cognitive Language REST client library for JavaScript + +Custom Wrapper Service + +**Please rely heavily on our [REST client docs](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/rest-clients.md) to use this library** + +Key links: + +- [Package (NPM)](https://www.npmjs.com/package/@msinternal/customWrapper) + +## Getting started + +### Currently supported environments + +- LTS versions of Node.js + +### Prerequisites + +- You must have an [Azure subscription](https://azure.microsoft.com/free/) to use this package. + +### Install the `@msinternal/customWrapper` package + +Install the Microsoft Cognitive Language REST client REST client library for JavaScript with `npm`: + +```bash +npm install @msinternal/customWrapper +``` + +### Create and authenticate a `MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoringClient` + +To use an [Azure Active Directory (AAD) token credential](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/identity/identity/samples/AzureIdentityExamples.md#authenticating-with-a-pre-fetched-access-token), +provide an instance of the desired credential type obtained from the +[@azure/identity](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials) library. + +To authenticate with AAD, you must first `npm` install [`@azure/identity`](https://www.npmjs.com/package/@azure/identity) + +After setup, you can choose which type of [credential](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials) from `@azure/identity` to use. +As an example, [DefaultAzureCredential](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#defaultazurecredential) +can be used to authenticate the client. + +Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables: +AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET + +## Troubleshooting + +### Logging + +Enabling logging may help uncover useful information about failures. In order to see a log of HTTP requests and responses, set the `AZURE_LOG_LEVEL` environment variable to `info`. Alternatively, logging can be enabled at runtime by calling `setLogLevel` in the `@azure/logger`: + +```javascript +const { setLogLevel } = require("@azure/logger"); + +setLogLevel("info"); +``` + +For more detailed instructions on how to enable logs, you can look at the [@azure/logger package docs](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/core/logger). diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/api-extractor.json b/packages/cadl-rlc-test/test/customWrapper/cadl-output/api-extractor.json new file mode 100644 index 0000000000..50d4182149 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/api-extractor.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "mainEntryPointFilePath": "./types/src/index.d.ts", + "docModel": { "enabled": true }, + "apiReport": { "enabled": true, "reportFolder": "./review" }, + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "", + "publicTrimmedFilePath": "./types/customWrapper.d.ts" + }, + "messages": { + "tsdocMessageReporting": { "default": { "logLevel": "none" } }, + "extractorMessageReporting": { + "ae-missing-release-tag": { "logLevel": "none" }, + "ae-unresolved-link": { "logLevel": "none" } + } + } +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/karma.conf.js b/packages/cadl-rlc-test/test/customWrapper/cadl-output/karma.conf.js new file mode 100644 index 0000000000..85f5daf9d3 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/karma.conf.js @@ -0,0 +1,135 @@ +// 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-edge-launcher", + "karma-firefox-launcher", + "karma-ie-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/cadl-rlc-test/test/customWrapper/cadl-output/openapi.json b/packages/cadl-rlc-test/test/customWrapper/cadl-output/openapi.json new file mode 100644 index 0000000000..8eeb2aa217 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/openapi.json @@ -0,0 +1,235 @@ +{ + "swagger": "2.0", + "info": { + "title": "Microsoft Cognitive Language Service - Analyze Text Authoring", + "version": "2022-05-15-preview", + "x-cadl-generated": [ + { + "emitter": "@azure-tools/cadl-autorest" + } + ] + }, + "schemes": [ + "https" + ], + "x-ms-parameterized-host": { + "hostTemplate": "{Endpoint}/language", + "useSchemePrefix": false, + "parameters": [ + { + "name": "Endpoint", + "in": "path", + "required": true, + "description": "The endpoint to use.", + "type": "string" + } + ] + }, + "produces": [ + "application/json" + ], + "consumes": [ + "application/json" + ], + "security": [ + { + "ApiKeyAuth": [] + } + ], + "securityDefinitions": { + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "Ocp-Apim-Subscription-Key" + } + }, + "tags": [], + "paths": { + "/authoring/analyze-text/deployments/{deploymentName}": { + "get": { + "operationId": "Deployments_GetDeployment", + "description": "Gets the details of a deployment.", + "parameters": [ + { + "name": "deploymentName", + "in": "path", + "required": true, + "description": "The name of the deployment.", + "type": "string" + }, + { + "$ref": "#/parameters/Azure.Core.Foundations.ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "The request has succeeded.", + "schema": { + "$ref": "#/definitions/Deployment" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/Azure.Core.Foundations.ErrorResponse" + } + } + } + }, + "put": { + "operationId": "Deployments_DeployProject", + "description": "Creates a new deployment or replaces an existing one.", + "parameters": [ + { + "name": "deploymentName", + "in": "path", + "required": true, + "description": "The name of the deployment.", + "type": "string" + }, + { + "$ref": "#/parameters/Azure.Core.Foundations.ApiVersionParameter" + }, + { + "name": "body", + "in": "body", + "required": false, + "description": "Parameter of type 'DeploymentCreationParameters' in the body.", + "schema": { + "$ref": "#/definitions/DeploymentCreationParameters" + } + } + ], + "responses": { + "200": { + "description": "The request has succeeded.", + "schema": { + "$ref": "#/definitions/Deployment" + } + }, + "201": { + "description": "A Deployment resource was successfully created.", + "schema": { + "$ref": "#/definitions/Deployment" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/Azure.Core.Foundations.ErrorResponse" + } + } + } + } + } + }, + "definitions": { + "Azure.Core.Foundations.Error": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "One of a server-defined set of error codes." + }, + "message": { + "type": "string", + "description": "A human-readable representation of the error." + }, + "target": { + "type": "string", + "description": "The target of the error." + }, + "details": { + "type": "array", + "items": { + "$ref": "#/definitions/Azure.Core.Foundations.Error" + }, + "x-ms-identifiers": [], + "x-cadl-name": "Azure.Core.Foundations.Error[]", + "description": "An array of details about specific errors that led to this reported error." + }, + "innererror": { + "$ref": "#/definitions/Azure.Core.Foundations.InnerError", + "description": "An object containing more specific information than the current object about the error." + } + }, + "description": "The error object.", + "required": [ + "code", + "message", + "details" + ] + }, + "Azure.Core.Foundations.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "$ref": "#/definitions/Azure.Core.Foundations.Error", + "description": "The error object." + } + }, + "description": "A response containing error details.", + "required": [ + "error" + ] + }, + "Azure.Core.Foundations.InnerError": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "One of a server-defined set of error codes." + }, + "innererror": { + "$ref": "#/definitions/Azure.Core.Foundations.InnerError", + "description": "Inner error." + } + }, + "description": "An object containing more specific information about the error. As per Microsoft One API guidelines - https://github.com/Microsoft/api-guidelines/blob/vNext/Guidelines.md#7102-error-condition-responses.", + "required": [ + "code" + ] + }, + "Deployment": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the deployment." + } + }, + "description": "The details of a project deployment.", + "required": [ + "name" + ] + }, + "DeploymentCreationParameters": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the deployment." + } + }, + "description": "Deployment resource creation parameters.", + "required": [ + "name" + ] + }, + "Endpoint": { + "type": "string", + "description": "The endpoint to use." + } + }, + "parameters": { + "Azure.Core.Foundations.ApiVersionParameter": { + "name": "api-version", + "in": "query", + "required": true, + "description": "The API version to use for this operation.", + "minLength": 1, + "type": "string", + "x-ms-parameter-location": "method" + } + } +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/package.json b/packages/cadl-rlc-test/test/customWrapper/cadl-output/package.json new file mode 100644 index 0000000000..92cec5b086 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/package.json @@ -0,0 +1,104 @@ +{ + "name": "@msinternal/customWrapper", + "sdk-type": "client", + "author": "Microsoft Corporation", + "version": "1.0.0-beta.1", + "description": "Custom Wrapper Service", + "keywords": ["node", "azure", "cloud", "typescript", "browser", "isomorphic"], + "license": "MIT", + "main": "dist/index.js", + "module": "./dist-esm/src/index.js", + "types": "./types/customWrapper.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/customWrapper.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\" \"test/**/*.ts\" \"samples-dev/**/*.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\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"", + "generate:client": "autorest --typescript swagger/README.md && npm run format", + "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.0.0-beta.10", + "@azure/core-rest-pipeline": "^1.8.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": "^8.2.0", + "eslint": "^8.0.0", + "mkdirp": "^1.0.4", + "prettier": "2.2.1", + "rimraf": "^3.0.0", + "source-map-support": "^0.5.9", + "typescript": "~4.8.0", + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-multi-entry": "^4.1.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": "^2.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-edge-launcher": "^0.4.2", + "karma-env-preprocessor": "^0.1.1", + "karma-firefox-launcher": "^1.1.0", + "karma-ie-launcher": "^1.0.0", + "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.3.8", + "karma": "^6.2.0", + "nyc": "^14.0.0" + }, + "browser": { + "./dist-esm/test/public/utils/env.js": "./dist-esm/test/public/utils/env.browser.js" + } +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/review/customWrapper.api.md b/packages/cadl-rlc-test/test/customWrapper/cadl-output/review/customWrapper.api.md new file mode 100644 index 0000000000..7b18e7a523 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/review/customWrapper.api.md @@ -0,0 +1,123 @@ +## API Report File for "@msinternal/customWrapper" + +> 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 { KeyCredential } from '@azure/core-auth'; +import { RequestParameters } from '@azure-rest/core-client'; +import { StreamableMethod } from '@azure-rest/core-client'; + +// @public +function createClient(Endpoint: string, credentials: KeyCredential, options?: ClientOptions): MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoringClient; +export default createClient; + +// @public +export interface DeploymentCreationParameters { + name: string; +} + +// @public +export interface DeploymentOutput { + name: string; +} + +// @public +export interface DeployProject200Response extends HttpResponse { + // (undocumented) + body: DeploymentOutput; + // (undocumented) + status: "200"; +} + +// @public +export interface DeployProject201Response extends HttpResponse { + // (undocumented) + body: DeploymentOutput; + // (undocumented) + status: "201"; +} + +// @public (undocumented) +export interface DeployProjectBodyParam { + body?: DeploymentCreationParameters; +} + +// @public (undocumented) +export interface DeployProjectDefaultResponse extends HttpResponse { + // (undocumented) + body: ErrorResponseOutput; + // (undocumented) + status: string; +} + +// @public (undocumented) +export type DeployProjectParameters = DeployProjectBodyParam & RequestParameters; + +// @public +export interface ErrorModelOutput { + code: string; + details: Array; + innererror?: InnerErrorOutput; + message: string; + target?: string; +} + +// @public +export interface ErrorResponseOutput { + error: ErrorModelOutput; +} + +// @public (undocumented) +export interface GetDeployment { + get(options?: GetDeploymentParameters): StreamableMethod; + put(options?: DeployProjectParameters): StreamableMethod; +} + +// @public +export interface GetDeployment200Response extends HttpResponse { + // (undocumented) + body: DeploymentOutput; + // (undocumented) + status: "200"; +} + +// @public (undocumented) +export interface GetDeploymentDefaultResponse extends HttpResponse { + // (undocumented) + body: ErrorResponseOutput; + // (undocumented) + status: string; +} + +// @public (undocumented) +export type GetDeploymentParameters = RequestParameters; + +// @public +export interface InnerErrorOutput { + code: string; + innererror?: InnerErrorOutput; +} + +// @public (undocumented) +export function isUnexpected(response: GetDeployment200Response | GetDeploymentDefaultResponse): response is GetDeploymentDefaultResponse; + +// @public (undocumented) +export function isUnexpected(response: DeployProject200Response | DeployProject201Response | DeployProjectDefaultResponse): response is DeployProjectDefaultResponse; + +// @public (undocumented) +export type MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoringClient = Client & { + path: Routes; +}; + +// @public (undocumented) +export interface Routes { + (path: "/authoring/analyze-text/deployments/{deploymentName}", deploymentName: string): GetDeployment; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/rollup.config.js b/packages/cadl-rlc-test/test/customWrapper/cadl-output/rollup.config.js new file mode 100644 index 0000000000..61251d7a8d --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/rollup.config.js @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import nodeResolve from "@rollup/plugin-node-resolve"; +import cjs from "@rollup/plugin-commonjs"; +import sourcemaps from "rollup-plugin-sourcemaps"; +import multiEntry from "@rollup/plugin-multi-entry"; +import json from "@rollup/plugin-json"; + +import nodeBuiltins from "builtin-modules"; + +// #region Warning Handler + +/** + * A function that can determine whether a rollup warning should be ignored. If + * the function returns `true`, then the warning will not be displayed. + */ + +function ignoreNiseSinonEval(warning) { + return ( + warning.code === "EVAL" && + warning.id && + (warning.id.includes("node_modules/nise") || + warning.id.includes("node_modules/sinon")) === true + ); +} + +function ignoreChaiCircularDependency(warning) { + return ( + warning.code === "CIRCULAR_DEPENDENCY" && + warning.importer && + warning.importer.includes("node_modules/chai") === true + ); +} + +const warningInhibitors = [ignoreChaiCircularDependency, ignoreNiseSinonEval]; + +/** + * Construct a warning handler for the shared rollup configuration + * that ignores certain warnings that are not relevant to testing. + */ +function makeOnWarnForTesting() { + return (warning, warn) => { + // If every inhibitor returns false (i.e. no inhibitors), then show the warning + if (warningInhibitors.every((inhib) => !inhib(warning))) { + warn(warning); + } + }; +} + +// #endregion + +function makeBrowserTestConfig() { + const config = { + input: { + include: ["dist-esm/test/**/*.spec.js"], + exclude: ["dist-esm/test/**/node/**"], + }, + output: { + file: `dist-test/index.browser.js`, + format: "umd", + sourcemap: true, + }, + preserveSymlinks: false, + plugins: [ + multiEntry({ exports: false }), + nodeResolve({ + mainFields: ["module", "browser"], + }), + cjs(), + json(), + sourcemaps(), + //viz({ filename: "dist-test/browser-stats.html", sourcemap: true }) + ], + onwarn: makeOnWarnForTesting(), + // Disable tree-shaking of test code. In rollup-plugin-node-resolve@5.0.0, + // rollup started respecting the "sideEffects" field in package.json. Since + // our package.json sets "sideEffects=false", this also applies to test + // code, which causes all tests to be removed by tree-shaking. + treeshake: false, + }; + + return config; +} + +const defaultConfigurationOptions = { + disableBrowserBundle: false, +}; + +export function makeConfig(pkg, options) { + options = { + ...defaultConfigurationOptions, + ...(options || {}), + }; + + const baseConfig = { + // Use the package's module field if it has one + input: pkg["module"] || "dist-esm/src/index.js", + external: [ + ...nodeBuiltins, + ...Object.keys(pkg.dependencies), + ...Object.keys(pkg.devDependencies), + ], + output: { file: "dist/index.js", format: "cjs", sourcemap: true }, + preserveSymlinks: false, + plugins: [sourcemaps(), nodeResolve()], + }; + + const config = [baseConfig]; + + if (!options.disableBrowserBundle) { + config.push(makeBrowserTestConfig()); + } + + return config; +} + +export default makeConfig(require("./package.json")); diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/clientDefinitions.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/clientDefinitions.ts new file mode 100644 index 0000000000..04ba4bb70d --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/clientDefinitions.ts @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { GetDeploymentParameters, DeployProjectParameters } from "./parameters"; +import { + GetDeployment200Response, + GetDeploymentDefaultResponse, + DeployProject200Response, + DeployProject201Response, + DeployProjectDefaultResponse, +} from "./responses"; +import { Client, StreamableMethod } from "@azure-rest/core-client"; + +export interface GetDeployment { + /** Gets the details of a deployment. */ + get( + options?: GetDeploymentParameters + ): StreamableMethod; + /** Creates a new deployment or replaces an existing one. */ + put( + options?: DeployProjectParameters + ): StreamableMethod< + | DeployProject200Response + | DeployProject201Response + | DeployProjectDefaultResponse + >; +} + +export interface Routes { + /** Resource for '/authoring/analyze-text/deployments/\{deploymentName\}' has methods for the following verbs: get, put */ + ( + path: "/authoring/analyze-text/deployments/{deploymentName}", + deploymentName: string + ): GetDeployment; +} + +export type MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoringClient = + Client & { + path: Routes; + }; diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/index.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/index.ts new file mode 100644 index 0000000000..9ae54d9dd4 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/index.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoring from "./microsoftCognitiveLanguageServiceAnalyzeTextAuthoring"; + +export * from "./microsoftCognitiveLanguageServiceAnalyzeTextAuthoring"; +export * from "./parameters"; +export * from "./responses"; +export * from "./clientDefinitions"; +export * from "./isUnexpected"; +export * from "./models"; +export * from "./outputModels"; + +export default MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoring; diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/isUnexpected.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/isUnexpected.ts new file mode 100644 index 0000000000..780015333f --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/isUnexpected.ts @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { + GetDeployment200Response, + GetDeploymentDefaultResponse, + DeployProject200Response, + DeployProject201Response, + DeployProjectDefaultResponse, +} from "./responses"; + +const responseMap: Record = { + "GET /authoring/analyze-text/deployments/{deploymentName}": ["200"], + "PUT /authoring/analyze-text/deployments/{deploymentName}": ["200", "201"], +}; + +export function isUnexpected( + response: GetDeployment200Response | GetDeploymentDefaultResponse +): response is GetDeploymentDefaultResponse; +export function isUnexpected( + response: + | DeployProject200Response + | DeployProject201Response + | DeployProjectDefaultResponse +): response is DeployProjectDefaultResponse; +export function isUnexpected( + response: + | GetDeployment200Response + | GetDeploymentDefaultResponse + | DeployProject200Response + | DeployProject201Response + | DeployProjectDefaultResponse +): response is GetDeploymentDefaultResponse | DeployProjectDefaultResponse { + 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/cadl-rlc-test/test/customWrapper/cadl-output/src/microsoftCognitiveLanguageServiceAnalyzeTextAuthoring.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/microsoftCognitiveLanguageServiceAnalyzeTextAuthoring.ts new file mode 100644 index 0000000000..45a2a9aa6f --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/microsoftCognitiveLanguageServiceAnalyzeTextAuthoring.ts @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { getClient, ClientOptions } from "@azure-rest/core-client"; +import { KeyCredential } from "@azure/core-auth"; +import { MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoringClient } from "./clientDefinitions"; + +/** + * Initialize a new instance of the class MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoringClient class. + * @param Endpoint type: string The endpoint to use. + * @param credentials type: KeyCredential + */ +export default function createClient( + Endpoint: string, + credentials: KeyCredential, + options: ClientOptions = {} +): MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoringClient { + const baseUrl = options.baseUrl ?? `${Endpoint}/language`; + options.apiVersion = options.apiVersion ?? "2022-05-15-preview"; + options = { + ...options, + credentials: { + apiKeyHeaderName: "Ocp-Apim-Subscription-Key", + }, + }; + + const userAgentInfo = `azsdk-js-customWrapper-rest/1.0.0-beta.1`; + const userAgentPrefix = + options.userAgentOptions && options.userAgentOptions.userAgentPrefix + ? `${options.userAgentOptions.userAgentPrefix} ${userAgentInfo}` + : `${userAgentInfo}`; + options = { + ...options, + userAgentOptions: { + userAgentPrefix, + }, + }; + + const client = getClient( + baseUrl, + credentials, + options + ) as MicrosoftCognitiveLanguageServiceAnalyzeTextAuthoringClient; + + return client; +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/models.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/models.ts new file mode 100644 index 0000000000..25bac67035 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/models.ts @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** Deployment resource creation parameters. */ +export interface DeploymentCreationParameters { + /** The name of the deployment. */ + name: string; +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/outputModels.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/outputModels.ts new file mode 100644 index 0000000000..3fdae5f2d8 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/outputModels.ts @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/** The details of a project deployment. */ +export interface DeploymentOutput { + /** The name of the deployment. */ + name: string; +} + +/** A response containing error details. */ +export interface ErrorResponseOutput { + /** The error object. */ + error: ErrorModelOutput; +} + +/** The error object. */ +export interface ErrorModelOutput { + /** One of a server-defined set of error codes. */ + code: string; + /** A human-readable representation of the error. */ + message: string; + /** The target of the error. */ + target?: string; + /** An array of details about specific errors that led to this reported error. */ + details: Array; + /** An object containing more specific information than the current object about the error. */ + innererror?: InnerErrorOutput; +} + +/** An object containing more specific information about the error. As per Microsoft One API guidelines - https://github.com/Microsoft/api-guidelines/blob/vNext/Guidelines.md#7102-error-condition-responses. */ +export interface InnerErrorOutput { + /** One of a server-defined set of error codes. */ + code: string; + /** Inner error. */ + innererror?: InnerErrorOutput; +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/parameters.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/parameters.ts new file mode 100644 index 0000000000..9bc628ab52 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/parameters.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { RequestParameters } from "@azure-rest/core-client"; +import { DeploymentCreationParameters } from "./models"; + +export type GetDeploymentParameters = RequestParameters; + +export interface DeployProjectBodyParam { + /** Parameter of type 'DeploymentCreationParameters' in the body. */ + body?: DeploymentCreationParameters; +} + +export type DeployProjectParameters = DeployProjectBodyParam & + RequestParameters; diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/responses.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/responses.ts new file mode 100644 index 0000000000..60ec009512 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/src/responses.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { HttpResponse } from "@azure-rest/core-client"; +import { DeploymentOutput, ErrorResponseOutput } from "./outputModels"; + +/** The request has succeeded. */ +export interface GetDeployment200Response extends HttpResponse { + status: "200"; + body: DeploymentOutput; +} + +export interface GetDeploymentDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponseOutput; +} + +/** The request has succeeded. */ +export interface DeployProject200Response extends HttpResponse { + status: "200"; + body: DeploymentOutput; +} + +/** A Deployment resource was successfully created. */ +export interface DeployProject201Response extends HttpResponse { + status: "201"; + body: DeploymentOutput; +} + +export interface DeployProjectDefaultResponse extends HttpResponse { + status: string; + body: ErrorResponseOutput; +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/sampleTest.spec.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/sampleTest.spec.ts new file mode 100644 index 0000000000..bce68e4286 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/sampleTest.spec.ts @@ -0,0 +1,23 @@ +// 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/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/env.browser.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/env.browser.ts new file mode 100644 index 0000000000..fd2aca680c --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/env.browser.ts @@ -0,0 +1,2 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/env.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/env.ts new file mode 100644 index 0000000000..0e06855b73 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/env.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as dotenv from "dotenv"; + +dotenv.config(); diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/recordedClient.ts b/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/recordedClient.ts new file mode 100644 index 0000000000..6cc58bc15e --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/test/public/utils/recordedClient.ts @@ -0,0 +1,29 @@ +// 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/cadl-rlc-test/test/customWrapper/cadl-output/tsconfig.json b/packages/cadl-rlc-test/test/customWrapper/cadl-output/tsconfig.json new file mode 100644 index 0000000000..9ca43fa318 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-output/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2017", + "module": "es6", + "lib": [], + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "sourceMap": true, + "importHelpers": true, + "strict": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "outDir": "./dist-esm", + "declarationDir": "./types" + }, + "include": ["./src/**/*.ts", "./test/**/*.ts"] +} diff --git a/packages/cadl-rlc-test/test/customWrapper/cadl-project.yaml b/packages/cadl-rlc-test/test/customWrapper/cadl-project.yaml new file mode 100644 index 0000000000..0fad991a13 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/cadl-project.yaml @@ -0,0 +1,7 @@ +emitters: + "@azure-tools/cadl-typescript": + azureSdkForJs: false + packageDetails: + name: "@msinternal/customWrapper" + description: "Custom Wrapper Service" + "@azure-tools/cadl-autorest": true diff --git a/packages/cadl-rlc-test/test/customWrapper/spec/azure-core-foundations-extensions.cadl b/packages/cadl-rlc-test/test/customWrapper/spec/azure-core-foundations-extensions.cadl new file mode 100644 index 0000000000..176303064c --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/spec/azure-core-foundations-extensions.cadl @@ -0,0 +1,74 @@ +using Cadl.Http; +using Cadl.Rest; +using Azure.Core; +using Azure.Core.Foundations; + +namespace Azure.Core.Foundations.Extensions; + +/* + This CADL file was created to customize the existing implementation from the foundations library. + In this file we have addressed the following issues: + 1. Avoid inlining of the models - required by ADP backend and also by the AutoRest. All models must be references and have schema definitions in the OpenApi spec. + 2. In ADP we are using slightly different model for LRO. It has additional state [Created] and the operation type property. + 3. The `CustomBodyWrapper` just adds the `@doc` to the body element to suppress warnings during the spec validation. + 4. The `CustomResourceOkResponse` wraps the with `@body`. + 5. The `CustomErrorResponse` adds missing header `x-ms-error-code` to the default error response + 6. For all LRO operations - add operation status location header and OK response where necessary to align with AutoRest code generator. + 7. The `CustomSingletonResource` has been introduced to allow operations on singleton child resources that have no identifier. +*/ + +@doc("for internal use") +@knownValues(DefaultLroTypesKV) +model DefaultLroType is string; +enum DefaultLroTypesKV { + Default: "default", +} + +@doc("List {name} resources", TResource) +op CustomResourceList< + TResource extends object, + TCustom extends Foundations.CustomizationFields = {} +> is Foundations.ResourceList< + TResource, + Foundations.CustomParameters, + Page +>; + +@doc("Creates or replaces a {name}", TResource) +@createsOrReplacesResource(TResource) +op CustomResourceCreateOrReplace< + TResource extends object, + TResourceCreateParams extends object +> is Foundations.ResourceOperation< + TResource, + TResourceCreateParams, + CustomResourceCreatedOrOkResponse +>; + +@doc("A wrapper for optional parameter in the body. The intent of model is to add description to 'body'") +model CustomBodyWrapper { + @doc("Parameter of type '{name}' in the body.", T) + @body + body?: T; +} + +@doc("A wrapper for required parameter in the body. The intent of model is to add description to 'body' and make it requred.") +model CustomRequiredBodyWrapper { + @doc("Parameter of type '{name}' in the body.", T) + @body + body: T; +} + +@doc("A {name} resource was successfully created.", T) +model CustomResourceCreatedResponse { + ...Cadl.Http.Response<201>; + @body body: T; +} + +model CustomResourceOkResponse { + ...Cadl.Http.Response<200>; + @body body: T; +} + +alias CustomResourceCreatedOrOkResponse = CustomResourceCreatedResponse | CustomResourceOkResponse; + diff --git a/packages/cadl-rlc-test/test/customWrapper/spec/main.cadl b/packages/cadl-rlc-test/test/customWrapper/spec/main.cadl new file mode 100644 index 0000000000..0a12284048 --- /dev/null +++ b/packages/cadl-rlc-test/test/customWrapper/spec/main.cadl @@ -0,0 +1,59 @@ +import "@cadl-lang/rest"; +import "@cadl-lang/versioning"; +import "@azure-tools/cadl-azure-core"; +import "./azure-core-foundations-extensions.cadl"; + +using Cadl.Http; +using Cadl.Rest; +using Cadl.Versioning; +using Azure.Core; +using Azure.Core.Foundations.Extensions; + +// NOTE: These features are missing: +// - Security definition for apiKey +@server( + "{Endpoint}/language", + "Language Service", + { + Endpoint: Endpoint, + } +) +@service({ + title: "Microsoft Cognitive Language Service - Analyze Text Authoring", + version: "2022-05-15-preview", +}) +@useAuth(ApiKeyAuth) +@versionedDependency(Azure.Core.Versions.v1_0_Preview_1) +@route("/authoring/analyze-text/") +namespace Azure.Language.Authoring; + +// Common Parameters +// TODO: Use the common parameter for this +@doc("The endpoint to use.") +model Endpoint is string; + +@doc("The details of a project deployment.") +model Deployment { + @doc("The name of the deployment.") + @key("deploymentName") + @segment("deployments") + name: string; +} + +@doc("Deployment resource creation parameters.") +@withVisibility("create") +model DeploymentCreationParameters { + ...Deployment; +} + +interface Deployments { + @doc("Gets the details of a deployment.") + getDeployment is ResourceRead; + + #suppress "@azure-tools/cadl-azure-core/long-running-polling-operation-required" "This operation does not follow the standard long-running operation pattern." + @doc("Creates a new deployment or replaces an existing one.") + deployProject is CustomResourceCreateOrReplace< + Deployment, + CustomBodyWrapper + >; +} \ No newline at end of file diff --git a/packages/cadl-typescript/src/modelUtils.ts b/packages/cadl-typescript/src/modelUtils.ts index a606db014e..807a1b1d86 100644 --- a/packages/cadl-typescript/src/modelUtils.ts +++ b/packages/cadl-typescript/src/modelUtils.ts @@ -43,11 +43,13 @@ import { Schema, SchemaContext } from "@azure-tools/rlc-common"; +import { getResourceOperation } from "@cadl-lang/rest"; import { getHeaderFieldName, getPathParamName, getQueryParamName, - isStatusCode + isStatusCode, + HttpOperation } from "@cadl-lang/rest/http"; import { getPagedResult } from "@azure-tools/cadl-azure-core"; @@ -63,7 +65,7 @@ export function getSchemaForType( usage?: SchemaContext[], needRef?: boolean ) { - const type = getEffectiveModelFromType(typeInput); + const type = getEffectiveModelFromType(program, typeInput); const builtinType = mapCadlTypeToTypeScript(program, type, usage); if (builtinType !== undefined) { // add in description elements for types derived from primitive types (SecureString, etc.) @@ -86,22 +88,6 @@ export function getSchemaForType( } else if (type.kind === "Enum") { return getSchemaForEnum(program, type); } - function getEffectiveModelFromType(type: Type) { - if (type.kind === "Model") { - const effective = getEffectiveModelType(program, type, isSchemaProperty); - if (effective.name) { - return effective; - } - } - function isSchemaProperty(property: ModelProperty) { - const headerInfo = getHeaderFieldName(program, property); - const queryInfo = getQueryParamName(program, property); - const pathInfo = getPathParamName(program, property); - const statusCodeInfo = isStatusCode(program, property); - return !(headerInfo || queryInfo || pathInfo || statusCodeInfo); - } - return type; - } if (isUnknownType(type)) { const returnType: any = { type: "unknown" }; if (usage && usage.includes(SchemaContext.Output)) { @@ -120,6 +106,22 @@ export function getSchemaForType( }); return undefined; } +export function getEffectiveModelFromType(program: Program, type: Type): Type { + if (type.kind === "Model") { + const effective = getEffectiveModelType(program, type, isSchemaProperty); + if (effective.name) { + return effective; + } + } + function isSchemaProperty(property: ModelProperty) { + const headerInfo = getHeaderFieldName(program, property); + const queryInfo = getQueryParamName(program, property); + const pathInfo = getPathParamName(program, property); + const statusCodeInfo = isStatusCode(program, property); + return !(headerInfo || queryInfo || pathInfo || statusCodeInfo); + } + return type; +} export function includeDerivedModel(model: Model): boolean { return ( !isTemplateDeclaration(model) && @@ -905,3 +907,44 @@ export function getFormattedPropertyDoc( } return propertyDoc ?? enhancedDocFromType; } + +export function getBodyType( + program: Program, + route: HttpOperation +): Type | undefined { + let bodyModel = route.parameters.bodyType; + if (bodyModel && bodyModel.kind === "Model" && route.operation) { + const resourceType = getResourceOperation( + program, + route.operation + )?.resourceType; + if (resourceType && route.responses && route.responses.length > 0) { + const resp = route.responses[0]; + if (resp && resp.responses && resp.responses.length > 0) { + const responseBody = resp.responses[0]?.body; + if (responseBody) { + const bodyTypeInResponse = getEffectiveModelFromType( + program, + responseBody.type + ); + // response body type is reosurce type, and request body type (if templated) contains resource type + if ( + bodyTypeInResponse === resourceType && + bodyModel.templateArguments && + bodyModel.templateArguments.some((it) => { + return it.kind === "Model" || it.kind === "Union" + ? it === bodyTypeInResponse + : false; + }) + ) { + bodyModel = resourceType; + } + } + } + } + if (resourceType && bodyModel.name === "") { + bodyModel = resourceType; + } + } + return bodyModel; +} diff --git a/packages/cadl-typescript/src/transform/transformParameters.ts b/packages/cadl-typescript/src/transform/transformParameters.ts index bc53d9f489..d48d1be23c 100644 --- a/packages/cadl-typescript/src/transform/transformParameters.ts +++ b/packages/cadl-typescript/src/transform/transformParameters.ts @@ -22,11 +22,11 @@ import { getTypeName, getSchemaForType, getBinaryType, - getFormattedPropertyDoc + getFormattedPropertyDoc, + getBodyType } from "../modelUtils.js"; import { isApiVersion } from "../paramUtil.js"; import { getOperationGroupName, isBinaryPayload } from "../operationUtil.js"; -import { getResourceOperation } from "@cadl-lang/rest"; import { Client, listOperationGroups, @@ -62,7 +62,6 @@ export function transformToParameterTypes( route: HttpOperation, operationGroup?: OperationGroup ) { - const operation = getResourceOperation(program, route.operation); const parameters = route.parameters; const rlcParameter: OperationParameter = { operationGroup: getOperationGroupName(operationGroup), @@ -76,17 +75,17 @@ export function transformToParameterTypes( // transform header param includeing content-type const headerParams = transformHeaderParameters(program, parameters); // transform body - let bodyType = undefined; - if (operation) { - bodyType = operation.resourceType; + const bodyType = getBodyType(program, route); + let bodyParameter = undefined; + if (bodyType && bodyType.kind === "Model") { + bodyParameter = transformBodyParameters( + program, + parameters, + headerParams, + outputImportedSet, + bodyType + ); } - const bodyParameter = transformBodyParameters( - program, - parameters, - headerParams, - outputImportedSet, - bodyType - ); rlcParameter.parameters.push({ parameters: [...queryParams, ...pathParams, ...headerParams], body: bodyParameter diff --git a/packages/cadl-typescript/src/transform/transformSchemas.ts b/packages/cadl-typescript/src/transform/transformSchemas.ts index b02140d706..9a2ebfe1d5 100644 --- a/packages/cadl-typescript/src/transform/transformSchemas.ts +++ b/packages/cadl-typescript/src/transform/transformSchemas.ts @@ -8,9 +8,12 @@ import { } from "@azure-tools/cadl-dpg"; import { Schema, SchemaContext } from "@azure-tools/rlc-common"; import { ignoreDiagnostics, Model, Program, Type } from "@cadl-lang/compiler"; -import { getResourceOperation } from "@cadl-lang/rest"; import { getHttpOperation, HttpOperation } from "@cadl-lang/rest/http"; -import { getSchemaForType, includeDerivedModel } from "../modelUtils.js"; +import { + getSchemaForType, + includeDerivedModel, + getBodyType +} from "../modelUtils.js"; export function transformSchemas(program: Program, client: Client) { const schemas: Schema[] = []; @@ -30,15 +33,9 @@ export function transformSchemas(program: Program, client: Client) { transformSchemaForRoute(route); } function transformSchemaForRoute(route: HttpOperation) { - if (route.parameters.bodyType) { - let bodyModel = route.parameters.bodyType; - const operation = getResourceOperation(program, route.operation); - if (operation) { - bodyModel = operation.resourceType; - } - if (bodyModel && bodyModel.kind === "Model") { - getGeneratedModels(bodyModel, SchemaContext.Input); - } + const bodyModel = getBodyType(program, route); + if (bodyModel && bodyModel.kind === "Model") { + getGeneratedModels(bodyModel, SchemaContext.Input); } for (const resp of route.responses) { for (const resps of resp.responses) {