diff --git a/sdk/core/core-http/lib/coreHttp.ts b/sdk/core/core-http/lib/coreHttp.ts index c3ca90f0a033..23ac18b21a9d 100644 --- a/sdk/core/core-http/lib/coreHttp.ts +++ b/sdk/core/core-http/lib/coreHttp.ts @@ -1,7 +1,15 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export { WebResource, HttpRequestBody, RequestPrepareOptions, HttpMethods, ParameterValue, RequestOptionsBase, TransferProgressEvent } from "./webResource"; +export { + WebResource, + HttpRequestBody, + RequestPrepareOptions, + HttpMethods, + ParameterValue, + RequestOptionsBase, + TransferProgressEvent +} from "./webResource"; export { DefaultHttpClient } from "./defaultHttpClient"; export { HttpClient } from "./httpClient"; export { HttpHeaders } from "./httpHeaders"; @@ -10,15 +18,27 @@ export { HttpPipelineLogger } from "./httpPipelineLogger"; export { HttpPipelineLogLevel } from "./httpPipelineLogLevel"; export { RestError } from "./restError"; export { OperationArguments } from "./operationArguments"; -export { OperationParameter, OperationQueryParameter, OperationURLParameter } from "./operationParameter"; +export { + OperationParameter, + OperationQueryParameter, + OperationURLParameter +} from "./operationParameter"; export { OperationResponse } from "./operationResponse"; export { OperationSpec } from "./operationSpec"; export { ServiceClient, ServiceClientOptions, flattenResponse } from "./serviceClient"; export { QueryCollectionFormat } from "./queryCollectionFormat"; export { Constants } from "./util/constants"; -export { BearerTokenAuthenticationPolicy, bearerTokenAuthenticationPolicy } from "./policies/bearerTokenAuthenticationPolicy"; +export { + BearerTokenAuthenticationPolicy, + bearerTokenAuthenticationPolicy +} from "./policies/bearerTokenAuthenticationPolicy"; export { logPolicy } from "./policies/logPolicy"; -export { BaseRequestPolicy, RequestPolicy, RequestPolicyFactory, RequestPolicyOptions } from "./policies/requestPolicy"; +export { + BaseRequestPolicy, + RequestPolicy, + RequestPolicyFactory, + RequestPolicyOptions +} from "./policies/requestPolicy"; export { generateClientRequestIdPolicy } from "./policies/generateClientRequestIdPolicy"; export { exponentialRetryPolicy } from "./policies/exponentialRetryPolicy"; export { systemErrorRetryPolicy } from "./policies/systemErrorRetryPolicy"; @@ -29,22 +49,50 @@ export { signingPolicy } from "./policies/signingPolicy"; export { userAgentPolicy, getDefaultUserAgentValue } from "./policies/userAgentPolicy"; export { deserializationPolicy, deserializeResponseBody } from "./policies/deserializationPolicy"; export { - MapperType, SimpleMapperType, CompositeMapperType, DictionaryMapperType, SequenceMapperType, EnumMapperType, - Mapper, BaseMapper, CompositeMapper, SequenceMapper, DictionaryMapper, EnumMapper, - MapperConstraints, PolymorphicDiscriminator, - Serializer, UrlParameterValue, serializeObject + MapperType, + SimpleMapperType, + CompositeMapperType, + DictionaryMapperType, + SequenceMapperType, + EnumMapperType, + Mapper, + BaseMapper, + CompositeMapper, + SequenceMapper, + DictionaryMapper, + EnumMapper, + MapperConstraints, + PolymorphicDiscriminator, + Serializer, + UrlParameterValue, + serializeObject } from "./serializer"; export { - stripRequest, stripResponse, delay, - executePromisesSequentially, generateUuid, encodeUri, ServiceCallback, - promiseToCallback, promiseToServiceCallback, isValidUuid, - applyMixins, isNode, isDuration + stripRequest, + stripResponse, + delay, + executePromisesSequentially, + generateUuid, + encodeUri, + ServiceCallback, + promiseToCallback, + promiseToServiceCallback, + isValidUuid, + applyMixins, + isNode, + isDuration } from "./util/utils"; export { URLBuilder, URLQuery } from "./url"; export { AbortSignalLike } from "@azure/abort-controller"; // Credentials -export { TokenCredential, GetTokenOptions, AccessToken, isTokenCredential, SimpleTokenCredential } from "@azure/core-auth"; +export { + TokenCredential, + GetTokenOptions, + AccessToken, + isTokenCredential, + SimpleTokenCredential +} from "@azure/core-auth"; export { AccessTokenCache, ExpiringAccessTokenCache } from "./credentials/accessTokenCache"; export { BasicAuthenticationCredentials } from "./credentials/basicAuthenticationCredentials"; export { ApiKeyCredentials, ApiKeyCredentialOptions } from "./credentials/apiKeyCredentials"; diff --git a/sdk/core/core-http/lib/util/utils.ts b/sdk/core/core-http/lib/util/utils.ts index 3740ee37f57c..fe18528ed20b 100644 --- a/sdk/core/core-http/lib/util/utils.ts +++ b/sdk/core/core-http/lib/util/utils.ts @@ -10,7 +10,11 @@ import { Constants } from "./constants"; /** * A constant that indicates whether the environment is node.js or browser based. */ -export const isNode = (typeof process !== "undefined") && !!process.version && !!process.versions && !!process.versions.node; +export const isNode = + typeof process !== "undefined" && + !!process.version && + !!process.versions && + !!process.versions.node; /** * Checks if a parsed URL is HTTPS @@ -77,7 +81,10 @@ export function stripRequest(request: WebResource): WebResource { * @return {boolean} True if the uuid is valid; false otherwise. */ export function isValidUuid(uuid: string): boolean { - const validUuidRegex = new RegExp("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", "ig"); + const validUuidRegex = new RegExp( + "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", + "ig" + ); return validUuidRegex.test(uuid); } @@ -89,7 +96,7 @@ export function isValidUuid(uuid: string): boolean { * * @return {any[]} An array of values of the given object. */ -export function objectValues(obj: { [key: string]: any; }): any[] { +export function objectValues(obj: { [key: string]: any }): any[] { const result: any[] = []; if (obj && obj instanceof Object) { for (const key in obj) { @@ -98,8 +105,11 @@ export function objectValues(obj: { [key: string]: any; }): any[] { } } } else { - throw new Error(`The provided object ${JSON.stringify(obj, undefined, 2)} is not a valid object that can be ` + - `enumerated to provide its values as an array.`); + const stringifiedObj = JSON.stringify(obj, undefined, 2); + throw new Error( + `The provided object ${stringifiedObj} is not a valid object that can be ` + + `enumerated to provide its values as an array.` + ); } return result; } @@ -140,7 +150,7 @@ export function executePromisesSequentially(promiseFactories: Array, kickst * * @returns {object} Returns the merged target object. */ -export function mergeObjects(source: { [key: string]: any; }, target: { [key: string]: any; }) { +export function mergeObjects(source: { [key: string]: any }, target: { [key: string]: any }) { Object.keys(source).forEach((key) => { target[key] = source[key]; }); @@ -168,7 +178,12 @@ export interface ServiceCallback { * @param {WebResource} [request] The raw/actual request sent to the server if an error did not occur. * @param {HttpOperationResponse} [response] The raw/actual response from the server if an error did not occur. */ - (err: Error | RestError | null, result?: TResult, request?: WebResource, response?: HttpOperationResponse): void; + ( + err: Error | RestError | null, + result?: TResult, + request?: WebResource, + response?: HttpOperationResponse + ): void; } /** @@ -182,11 +197,14 @@ export function promiseToCallback(promise: Promise): Function { throw new Error("The provided input is not a Promise."); } return (cb: Function): void => { - promise.then((data: any) => { - cb(undefined, data); - }, (err: Error) => { - cb(err); - }); + promise.then( + (data: any) => { + cb(undefined, data); + }, + (err: Error) => { + cb(err); + } + ); }; } @@ -200,11 +218,14 @@ export function promiseToServiceCallback(promise: Promise): void => { - promise.then((data: HttpOperationResponse) => { - process.nextTick(cb, undefined, data.parsedBody as T, data.request, data); - }, (err: Error) => { - process.nextTick(cb, err); - }); + promise.then( + (data: HttpOperationResponse) => { + process.nextTick(cb, undefined, data.parsedBody as T, data.request, data); + }, + (err: Error) => { + process.nextTick(cb, err); + } + ); }; } @@ -221,8 +242,8 @@ export function prepareXMLRootList(obj: any, elementName: string) { * @param {Array} sourceCtors An array of source objects from which the properties need to be taken. */ export function applyMixins(targetCtor: any, sourceCtors: any[]): void { - sourceCtors.forEach(sourceCtors => { - Object.getOwnPropertyNames(sourceCtors.prototype).forEach(name => { + sourceCtors.forEach((sourceCtors) => { + Object.getOwnPropertyNames(sourceCtors.prototype).forEach((name) => { targetCtor.prototype[name] = sourceCtors.prototype[name]; }); }); @@ -246,7 +267,11 @@ export function isDuration(value: string): boolean { * @param {string} replaceValue The value to replace searchValue with in the value argument. * @returns {string | undefined} The value where each instance of searchValue was replaced with replacedValue. */ -export function replaceAll(value: string | undefined, searchValue: string, replaceValue: string): string | undefined { +export function replaceAll( + value: string | undefined, + searchValue: string, + replaceValue: string +): string | undefined { return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || ""); } diff --git a/sdk/core/core-http/lib/util/xml.browser.ts b/sdk/core/core-http/lib/util/xml.browser.ts index 059b329d141a..03cef5783f76 100644 --- a/sdk/core/core-http/lib/util/xml.browser.ts +++ b/sdk/core/core-http/lib/util/xml.browser.ts @@ -16,7 +16,8 @@ export function parseXML(str: string): Promise { let errorNS = ""; try { - errorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0].namespaceURI!; + errorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0] + .namespaceURI!; } catch (ignored) { // Most browsers will return a document containing , but IE will throw. } @@ -48,7 +49,12 @@ function domToObject(node: Node): any { const childNodeCount: number = node.childNodes.length; const firstChildNode: Node = node.childNodes[0]; - const onlyChildTextValue: string | undefined = (firstChildNode && childNodeCount === 1 && firstChildNode.nodeType === Node.TEXT_NODE && firstChildNode.nodeValue) || undefined; + const onlyChildTextValue: string | undefined = + (firstChildNode && + childNodeCount === 1 && + firstChildNode.nodeType === Node.TEXT_NODE && + firstChildNode.nodeValue) || + undefined; const elementWithAttributes: Element | undefined = asElementWithAttributes(node); if (elementWithAttributes) { @@ -93,12 +99,14 @@ const doc = document.implementation.createDocument(null, null, null); const serializer = new XMLSerializer(); export function stringifyXML(obj: any, opts?: { rootName?: string }) { - const rootName = opts && opts.rootName || "root"; + const rootName = (opts && opts.rootName) || "root"; const dom = buildNode(obj, rootName)[0]; - return '' + serializer.serializeToString(dom); + return ( + '' + serializer.serializeToString(dom) + ); } -function buildAttributes(attrs: { [key: string]: { toString(): string; } }): Attr[] { +function buildAttributes(attrs: { [key: string]: { toString(): string } }): Attr[] { const result = []; for (const key of Object.keys(attrs)) { const attr = doc.createAttribute(key); @@ -113,8 +121,7 @@ function buildNode(obj: any, elementName: string): Node[] { const elem = doc.createElement(elementName); elem.textContent = obj.toString(); return [elem]; - } - else if (Array.isArray(obj)) { + } else if (Array.isArray(obj)) { const result = []; for (const arrayElem of obj) { for (const child of buildNode(arrayElem, elementName)) { @@ -136,8 +143,7 @@ function buildNode(obj: any, elementName: string): Node[] { } } return [elem]; - } - else { + } else { throw new Error(`Illegal value passed to buildObject: ${obj}`); } } diff --git a/sdk/core/core-http/lib/webResource.ts b/sdk/core/core-http/lib/webResource.ts index cac837cae01c..201a66533b3a 100644 --- a/sdk/core/core-http/lib/webResource.ts +++ b/sdk/core/core-http/lib/webResource.ts @@ -10,8 +10,21 @@ import { OperationResponse } from "./operationResponse"; import { ProxySettings } from "./serviceClient"; import { AbortSignalLike } from "@azure/abort-controller"; -export type HttpMethods = "GET" | "PUT" | "POST" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS" | "TRACE"; -export type HttpRequestBody = Blob | string | ArrayBuffer | ArrayBufferView | (() => NodeJS.ReadableStream); +export type HttpMethods = + | "GET" + | "PUT" + | "POST" + | "DELETE" + | "PATCH" + | "HEAD" + | "OPTIONS" + | "TRACE"; +export type HttpRequestBody = + | Blob + | string + | ArrayBuffer + | ArrayBufferView + | (() => NodeJS.ReadableStream); /** * Fired in response to upload or download progress. @@ -20,7 +33,7 @@ export type TransferProgressEvent = { /** * The number of bytes loaded so far. */ - loadedBytes: number + loadedBytes: number; }; /** @@ -50,9 +63,12 @@ export class WebResource { * HttpOperationResponse combination. If this is undefined, then a simple status code lookup will * be used. */ - operationResponseGetter?: (operationSpec: OperationSpec, response: HttpOperationResponse) => (undefined | OperationResponse); + operationResponseGetter?: ( + operationSpec: OperationSpec, + response: HttpOperationResponse + ) => undefined | OperationResponse; formData?: any; - query?: { [key: string]: any; }; + query?: { [key: string]: any }; operationSpec?: OperationSpec; withCredentials: boolean; timeout: number; @@ -71,8 +87,8 @@ export class WebResource { url?: string, method?: HttpMethods, body?: any, - query?: { [key: string]: any; }, - headers?: { [key: string]: any; } | HttpHeaders, + query?: { [key: string]: any }, + headers?: { [key: string]: any } | HttpHeaders, streamResponseBody?: boolean, withCredentials?: boolean, abortSignal?: AbortSignalLike, @@ -80,12 +96,12 @@ export class WebResource { onUploadProgress?: (progress: TransferProgressEvent) => void, onDownloadProgress?: (progress: TransferProgressEvent) => void, proxySettings?: ProxySettings, - keepAlive?: boolean) { - + keepAlive?: boolean + ) { this.streamResponseBody = streamResponseBody; this.url = url || ""; this.method = method || "GET"; - this.headers = (headers instanceof HttpHeaders ? headers : new HttpHeaders(headers)); + this.headers = headers instanceof HttpHeaders ? headers : new HttpHeaders(headers); this.body = body; this.query = query; this.formData = undefined; @@ -127,18 +143,22 @@ export class WebResource { } if (options.url && options.pathTemplate) { - throw new Error("options.url and options.pathTemplate are mutually exclusive. Please provide exactly one of them."); + throw new Error( + "options.url and options.pathTemplate are mutually exclusive. Please provide exactly one of them." + ); } - - if ((options.pathTemplate == undefined || typeof options.pathTemplate.valueOf() !== "string") && (options.url == undefined || typeof options.url.valueOf() !== "string")) { + if ( + (options.pathTemplate == undefined || typeof options.pathTemplate.valueOf() !== "string") && + (options.url == undefined || typeof options.url.valueOf() !== "string") + ) { throw new Error("Please provide exactly one of options.pathTemplate or options.url."); } // set the url if it is provided. if (options.url) { if (typeof options.url !== "string") { - throw new Error("options.url must be of type \"string\"."); + throw new Error('options.url must be of type "string".'); } this.url = options.url; } @@ -147,35 +167,52 @@ export class WebResource { if (options.method) { const validMethods = ["GET", "PUT", "HEAD", "DELETE", "OPTIONS", "POST", "PATCH", "TRACE"]; if (validMethods.indexOf(options.method.toUpperCase()) === -1) { - throw new Error("The provided method \"" + options.method + "\" is invalid. Supported HTTP methods are: " + JSON.stringify(validMethods)); + throw new Error( + 'The provided method "' + + options.method + + '" is invalid. Supported HTTP methods are: ' + + JSON.stringify(validMethods) + ); } } - this.method = (options.method.toUpperCase() as HttpMethods); + this.method = options.method.toUpperCase() as HttpMethods; // construct the url if path template is provided if (options.pathTemplate) { const { pathTemplate, pathParameters } = options; if (typeof pathTemplate !== "string") { - throw new Error("options.pathTemplate must be of type \"string\"."); + throw new Error('options.pathTemplate must be of type "string".'); } if (!options.baseUrl) { options.baseUrl = "https://management.azure.com"; } const baseUrl = options.baseUrl; - let url = baseUrl + (baseUrl.endsWith("/") ? "" : "/") + (pathTemplate.startsWith("/") ? pathTemplate.slice(1) : pathTemplate); - const segments = url.match(/({\w*\s*\w*})/ig); + let url = + baseUrl + + (baseUrl.endsWith("/") ? "" : "/") + + (pathTemplate.startsWith("/") ? pathTemplate.slice(1) : pathTemplate); + const segments = url.match(/({\w*\s*\w*})/gi); if (segments && segments.length) { if (!pathParameters) { - throw new Error(`pathTemplate: ${pathTemplate} has been provided. Hence, options.pathParameters must also be provided.`); + throw new Error( + `pathTemplate: ${pathTemplate} has been provided. Hence, options.pathParameters must also be provided.` + ); } - segments.forEach(function (item) { + segments.forEach(function(item) { const pathParamName = item.slice(1, -1); const pathParam = (pathParameters as { [key: string]: any })[pathParamName]; - if (pathParam === null || pathParam === undefined || !(typeof pathParam === "string" || typeof pathParam === "object")) { - throw new Error(`pathTemplate: ${pathTemplate} contains the path parameter ${pathParamName}` + - ` however, it is not present in ${pathParameters} - ${JSON.stringify(pathParameters, undefined, 2)}.` + - `The value of the path parameter can either be a "string" of the form { ${pathParamName}: "some sample value" } or ` + - `it can be an "object" of the form { "${pathParamName}": { value: "some sample value", skipUrlEncoding: true } }.`); + if ( + pathParam === null || + pathParam === undefined || + !(typeof pathParam === "string" || typeof pathParam === "object") + ) { + const stringifiedPathParameters = JSON.stringify(pathParameters, undefined, 2); + throw new Error( + `pathTemplate: ${pathTemplate} contains the path parameter ${pathParamName}` + + ` however, it is not present in parameters: ${stringifiedPathParameters}.` + + `The value of the path parameter can either be a "string" of the form { ${pathParamName}: "some sample value" } or ` + + `it can be an "object" of the form { "${pathParamName}": { value: "some sample value", skipUrlEncoding: true } }.` + ); } if (typeof pathParam.valueOf() === "string") { @@ -184,7 +221,9 @@ export class WebResource { if (typeof pathParam.valueOf() === "object") { if (!pathParam.value) { - throw new Error(`options.pathParameters[${pathParamName}] is of type "object" but it does not contain a "value" property.`); + throw new Error( + `options.pathParameters[${pathParamName}] is of type "object" but it does not contain a "value" property.` + ); } if (pathParam.skipUrlEncoding) { url = url.replace(item, pathParam.value); @@ -201,9 +240,11 @@ export class WebResource { if (options.queryParameters) { const queryParameters = options.queryParameters; if (typeof queryParameters !== "object") { - throw new Error(`options.queryParameters must be of type object. It should be a JSON object ` + - `of "query-parameter-name" as the key and the "query-parameter-value" as the value. ` + - `The "query-parameter-value" may be fo type "string" or an "object" of the form { value: "query-parameter-value", skipUrlEncoding: true }.`); + throw new Error( + `options.queryParameters must be of type object. It should be a JSON object ` + + `of "query-parameter-name" as the key and the "query-parameter-value" as the value. ` + + `The "query-parameter-value" may be fo type "string" or an "object" of the form { value: "query-parameter-value", skipUrlEncoding: true }.` + ); } // append question mark if it is not present in the url if (this.url && this.url.indexOf("?") === -1) { @@ -219,10 +260,11 @@ export class WebResource { if (typeof queryParam === "string") { queryParams.push(queryParamName + "=" + encodeURIComponent(queryParam)); this.query[queryParamName] = encodeURIComponent(queryParam); - } - else if (typeof queryParam === "object") { + } else if (typeof queryParam === "object") { if (!queryParam.value) { - throw new Error(`options.queryParameters[${queryParamName}] is of type "object" but it does not contain a "value" property.`); + throw new Error( + `options.queryParameters[${queryParamName}] is of type "object" but it does not contain a "value" property.` + ); } if (queryParam.skipUrlEncoding) { queryParams.push(queryParamName + "=" + queryParam.value); @@ -233,7 +275,7 @@ export class WebResource { } } } - }// end-of-for + } // end-of-for // append the queryString this.url += queryParams.join("&"); } @@ -272,7 +314,11 @@ export class WebResource { } } else { if (options.serializationMapper) { - this.body = new Serializer(options.mappers).serialize(options.serializationMapper, options.body, "requestBody"); + this.body = new Serializer(options.mappers).serialize( + options.serializationMapper, + options.body, + "requestBody" + ); } if (!options.disableJsonStringifyOnBody) { this.body = JSON.stringify(options.body); @@ -303,7 +349,8 @@ export class WebResource { this.abortSignal, this.timeout, this.onUploadProgress, - this.onDownloadProgress); + this.onDownloadProgress + ); if (this.formData) { result.formData = this.formData; diff --git a/sdk/core/core-http/webpack.testconfig.ts b/sdk/core/core-http/webpack.testconfig.ts index 1b34aeddf647..89ea3b890d7c 100644 --- a/sdk/core/core-http/webpack.testconfig.ts +++ b/sdk/core/core-http/webpack.testconfig.ts @@ -3,7 +3,7 @@ import * as glob from "glob"; import * as path from "path"; const config: webpack.Configuration = { - entry: glob.sync(path.join(__dirname, "test/**/*[^node\.].ts")), + entry: glob.sync(path.join(__dirname, "test/**/*[^node.].ts")), mode: "development", devtool: "source-map", stats: { @@ -27,11 +27,26 @@ const config: webpack.Configuration = { path: path.resolve(__dirname, "test") }, plugins: [ - new webpack.NormalModuleReplacementPlugin(/(\.).+util\/base64/, path.resolve(__dirname, "./lib/util/base64.browser.ts")), - new webpack.NormalModuleReplacementPlugin(/(\.).+util\/xml/, path.resolve(__dirname, "./lib/util/xml.browser.ts")), - new webpack.NormalModuleReplacementPlugin(/(\.).+defaultHttpClient/, path.resolve(__dirname, "./lib/defaultHttpClient.browser.ts")), - new webpack.NormalModuleReplacementPlugin(/(\.).+msRestUserAgentPolicy/, path.resolve(__dirname, "./lib/policies/msRestUserAgentPolicy.browser.ts")), - new webpack.NormalModuleReplacementPlugin(/(\.).+proxyPolicy/, path.resolve(__dirname, "./lib/policies/proxyPolicy.browser.ts")) + new webpack.NormalModuleReplacementPlugin( + /(\.).+util\/base64/, + path.resolve(__dirname, "./lib/util/base64.browser.ts") + ), + new webpack.NormalModuleReplacementPlugin( + /(\.).+util\/xml/, + path.resolve(__dirname, "./lib/util/xml.browser.ts") + ), + new webpack.NormalModuleReplacementPlugin( + /(\.).+defaultHttpClient/, + path.resolve(__dirname, "./lib/defaultHttpClient.browser.ts") + ), + new webpack.NormalModuleReplacementPlugin( + /(\.).+msRestUserAgentPolicy/, + path.resolve(__dirname, "./lib/policies/msRestUserAgentPolicy.browser.ts") + ), + new webpack.NormalModuleReplacementPlugin( + /(\.).+proxyPolicy/, + path.resolve(__dirname, "./lib/policies/proxyPolicy.browser.ts") + ) ], module: { rules: [ @@ -55,7 +70,7 @@ const config: webpack.Configuration = { tls: "empty", tty: false, tunnel: "empty", - v8: false, + v8: false } };