utils.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License. See License.txt in the project root for license information.
  3. import uuidv4 from "uuid/v4";
  4. import { HttpOperationResponse } from "../httpOperationResponse";
  5. import { RestError } from "../restError";
  6. import { WebResource } from "../webResource";
  7. import { Constants } from "./constants";
  8. /**
  9. * A constant that indicates whether the environment is node.js or browser based.
  10. */
  11. export const isNode = (typeof process !== "undefined") && !!process.version && !!process.versions && !!process.versions.node;
  12. /**
  13. * Checks if a parsed URL is HTTPS
  14. *
  15. * @param {object} urlToCheck The url to check
  16. * @return {boolean} True if the URL is HTTPS; false otherwise.
  17. */
  18. export function urlIsHTTPS(urlToCheck: { protocol: string }): boolean {
  19. return urlToCheck.protocol.toLowerCase() === Constants.HTTPS;
  20. }
  21. /**
  22. * Encodes an URI.
  23. *
  24. * @param {string} uri The URI to be encoded.
  25. * @return {string} The encoded URI.
  26. */
  27. export function encodeUri(uri: string): string {
  28. return encodeURIComponent(uri)
  29. .replace(/!/g, "%21")
  30. .replace(/"/g, "%27")
  31. .replace(/\(/g, "%28")
  32. .replace(/\)/g, "%29")
  33. .replace(/\*/g, "%2A");
  34. }
  35. /**
  36. * Returns a stripped version of the Http Response which only contains body,
  37. * headers and the status.
  38. *
  39. * @param {HttpOperationResponse} response The Http Response
  40. *
  41. * @return {object} The stripped version of Http Response.
  42. */
  43. export function stripResponse(response: HttpOperationResponse): any {
  44. const strippedResponse: any = {};
  45. strippedResponse.body = response.bodyAsText;
  46. strippedResponse.headers = response.headers;
  47. strippedResponse.status = response.status;
  48. return strippedResponse;
  49. }
  50. /**
  51. * Returns a stripped version of the Http Request that does not contain the
  52. * Authorization header.
  53. *
  54. * @param {WebResource} request The Http Request object
  55. *
  56. * @return {WebResource} The stripped version of Http Request.
  57. */
  58. export function stripRequest(request: WebResource): WebResource {
  59. const strippedRequest = request.clone();
  60. if (strippedRequest.headers) {
  61. strippedRequest.headers.remove("authorization");
  62. }
  63. return strippedRequest;
  64. }
  65. /**
  66. * Validates the given uuid as a string
  67. *
  68. * @param {string} uuid The uuid as a string that needs to be validated
  69. *
  70. * @return {boolean} True if the uuid is valid; false otherwise.
  71. */
  72. export function isValidUuid(uuid: string): boolean {
  73. 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");
  74. return validUuidRegex.test(uuid);
  75. }
  76. /**
  77. * Provides an array of values of an object. For example
  78. * for a given object { "a": "foo", "b": "bar" }, the method returns ["foo", "bar"].
  79. *
  80. * @param {object} obj An object whose properties need to be enumerated so that it"s values can be provided as an array
  81. *
  82. * @return {any[]} An array of values of the given object.
  83. */
  84. export function objectValues(obj: { [key: string]: any; }): any[] {
  85. const result: any[] = [];
  86. if (obj && obj instanceof Object) {
  87. for (const key in obj) {
  88. if (obj.hasOwnProperty(key)) {
  89. result.push((<any>obj)[key]);
  90. }
  91. }
  92. } else {
  93. throw new Error(`The provided object ${JSON.stringify(obj, undefined, 2)} is not a valid object that can be ` +
  94. `enumerated to provide its values as an array.`);
  95. }
  96. return result;
  97. }
  98. /**
  99. * Generated UUID
  100. *
  101. * @return {string} RFC4122 v4 UUID.
  102. */
  103. export function generateUuid(): string {
  104. return uuidv4();
  105. }
  106. /**
  107. * Executes an array of promises sequentially. Inspiration of this method is here:
  108. * https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html. An awesome blog on promises!
  109. *
  110. * @param {Array} promiseFactories An array of promise factories(A function that return a promise)
  111. *
  112. * @param {any} [kickstart] Input to the first promise that is used to kickstart the promise chain.
  113. * If not provided then the promise chain starts with undefined.
  114. *
  115. * @return A chain of resolved or rejected promises
  116. */
  117. export function executePromisesSequentially(promiseFactories: Array<any>, kickstart: any) {
  118. let result = Promise.resolve(kickstart);
  119. promiseFactories.forEach((promiseFactory) => {
  120. result = result.then(promiseFactory);
  121. });
  122. return result;
  123. }
  124. /**
  125. * Merges source object into the target object
  126. * @param {object} source The object that needs to be merged
  127. *
  128. * @param {object} target The object to be merged into
  129. *
  130. * @returns {object} Returns the merged target object.
  131. */
  132. export function mergeObjects(source: { [key: string]: any; }, target: { [key: string]: any; }) {
  133. Object.keys(source).forEach((key) => {
  134. target[key] = source[key];
  135. });
  136. return target;
  137. }
  138. /**
  139. * A wrapper for setTimeout that resolves a promise after t milliseconds.
  140. * @param {number} t The number of milliseconds to be delayed.
  141. * @param {T} value The value to be resolved with after a timeout of t milliseconds.
  142. * @returns {Promise<T>} Resolved promise
  143. */
  144. export function delay<T>(t: number, value?: T): Promise<T> {
  145. return new Promise((resolve) => setTimeout(() => resolve(value), t));
  146. }
  147. /**
  148. * Service callback that is returned for REST requests initiated by the service client.
  149. */
  150. export interface ServiceCallback<TResult> {
  151. /**
  152. * A method that will be invoked as a callback to a service function.
  153. * @param {Error | RestError | null} err The error occurred if any, while executing the request; otherwise null.
  154. * @param {TResult} [result] The deserialized response body if an error did not occur.
  155. * @param {WebResource} [request] The raw/actual request sent to the server if an error did not occur.
  156. * @param {HttpOperationResponse} [response] The raw/actual response from the server if an error did not occur.
  157. */
  158. (err: Error | RestError | null, result?: TResult, request?: WebResource, response?: HttpOperationResponse): void;
  159. }
  160. /**
  161. * Converts a Promise to a callback.
  162. * @param {Promise<any>} promise The Promise to be converted to a callback
  163. * @returns {Function} A function that takes the callback (cb: Function): void
  164. * @deprecated generated code should instead depend on responseToBody
  165. */
  166. export function promiseToCallback(promise: Promise<any>): Function {
  167. if (typeof promise.then !== "function") {
  168. throw new Error("The provided input is not a Promise.");
  169. }
  170. return (cb: Function): void => {
  171. promise.then((data: any) => {
  172. cb(undefined, data);
  173. }, (err: Error) => {
  174. cb(err);
  175. });
  176. };
  177. }
  178. /**
  179. * Converts a Promise to a service callback.
  180. * @param {Promise<HttpOperationResponse>} promise - The Promise of HttpOperationResponse to be converted to a service callback
  181. * @returns {Function} A function that takes the service callback (cb: ServiceCallback<T>): void
  182. */
  183. export function promiseToServiceCallback<T>(promise: Promise<HttpOperationResponse>): Function {
  184. if (typeof promise.then !== "function") {
  185. throw new Error("The provided input is not a Promise.");
  186. }
  187. return (cb: ServiceCallback<T>): void => {
  188. promise.then((data: HttpOperationResponse) => {
  189. process.nextTick(cb, undefined, data.parsedBody as T, data.request, data);
  190. }, (err: Error) => {
  191. process.nextTick(cb, err);
  192. });
  193. };
  194. }
  195. export function prepareXMLRootList(obj: any, elementName: string) {
  196. if (!Array.isArray(obj)) {
  197. obj = [obj];
  198. }
  199. return { [elementName]: obj };
  200. }
  201. /**
  202. * Applies the properties on the prototype of sourceCtors to the prototype of targetCtor
  203. * @param {object} targetCtor The target object on which the properties need to be applied.
  204. * @param {Array<object>} sourceCtors An array of source objects from which the properties need to be taken.
  205. */
  206. export function applyMixins(targetCtor: any, sourceCtors: any[]): void {
  207. sourceCtors.forEach(sourceCtors => {
  208. Object.getOwnPropertyNames(sourceCtors.prototype).forEach(name => {
  209. targetCtor.prototype[name] = sourceCtors.prototype[name];
  210. });
  211. });
  212. }
  213. const validateISODuration = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
  214. /**
  215. * Indicates whether the given string is in ISO 8601 format.
  216. * @param {string} value The value to be validated for ISO 8601 duration format.
  217. * @return {boolean} `true` if valid, `false` otherwise.
  218. */
  219. export function isDuration(value: string): boolean {
  220. return validateISODuration.test(value);
  221. }
  222. /**
  223. * Replace all of the instances of searchValue in value with the provided replaceValue.
  224. * @param {string | undefined} value The value to search and replace in.
  225. * @param {string} searchValue The value to search for in the value argument.
  226. * @param {string} replaceValue The value to replace searchValue with in the value argument.
  227. * @returns {string | undefined} The value where each instance of searchValue was replaced with replacedValue.
  228. */
  229. export function replaceAll(value: string | undefined, searchValue: string, replaceValue: string): string | undefined {
  230. return !value || !searchValue ? value : value.split(searchValue).join(replaceValue || "");
  231. }