index.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.noop = exports.defaults = exports.Debug = exports.zipMap = exports.CONNECTION_CLOSED_ERROR_MSG = exports.shuffle = exports.sample = exports.resolveTLSProfile = exports.parseURL = exports.optimizeErrorStack = exports.toArg = exports.convertMapToArray = exports.convertObjectToArray = exports.timeout = exports.packObject = exports.isInt = exports.wrapMultiResult = exports.convertBufferToString = void 0;
  4. const url_1 = require("url");
  5. const lodash_1 = require("./lodash");
  6. Object.defineProperty(exports, "defaults", { enumerable: true, get: function () { return lodash_1.defaults; } });
  7. Object.defineProperty(exports, "noop", { enumerable: true, get: function () { return lodash_1.noop; } });
  8. const debug_1 = require("./debug");
  9. exports.Debug = debug_1.default;
  10. const TLSProfiles_1 = require("../constants/TLSProfiles");
  11. /**
  12. * Convert a buffer to string, supports buffer array
  13. *
  14. * @example
  15. * ```js
  16. * const input = [Buffer.from('foo'), [Buffer.from('bar')]]
  17. * const res = convertBufferToString(input, 'utf8')
  18. * expect(res).to.eql(['foo', ['bar']])
  19. * ```
  20. */
  21. function convertBufferToString(value, encoding) {
  22. if (value instanceof Buffer) {
  23. return value.toString(encoding);
  24. }
  25. if (Array.isArray(value)) {
  26. const length = value.length;
  27. const res = Array(length);
  28. for (let i = 0; i < length; ++i) {
  29. res[i] =
  30. value[i] instanceof Buffer && encoding === "utf8"
  31. ? value[i].toString()
  32. : convertBufferToString(value[i], encoding);
  33. }
  34. return res;
  35. }
  36. return value;
  37. }
  38. exports.convertBufferToString = convertBufferToString;
  39. /**
  40. * Convert a list of results to node-style
  41. *
  42. * @example
  43. * ```js
  44. * const input = ['a', 'b', new Error('c'), 'd']
  45. * const output = exports.wrapMultiResult(input)
  46. * expect(output).to.eql([[null, 'a'], [null, 'b'], [new Error('c')], [null, 'd'])
  47. * ```
  48. */
  49. function wrapMultiResult(arr) {
  50. // When using WATCH/EXEC transactions, the EXEC will return
  51. // a null instead of an array
  52. if (!arr) {
  53. return null;
  54. }
  55. const result = [];
  56. const length = arr.length;
  57. for (let i = 0; i < length; ++i) {
  58. const item = arr[i];
  59. if (item instanceof Error) {
  60. result.push([item]);
  61. }
  62. else {
  63. result.push([null, item]);
  64. }
  65. }
  66. return result;
  67. }
  68. exports.wrapMultiResult = wrapMultiResult;
  69. /**
  70. * Detect if the argument is a int
  71. * @example
  72. * ```js
  73. * > isInt('123')
  74. * true
  75. * > isInt('123.3')
  76. * false
  77. * > isInt('1x')
  78. * false
  79. * > isInt(123)
  80. * true
  81. * > isInt(true)
  82. * false
  83. * ```
  84. */
  85. function isInt(value) {
  86. const x = parseFloat(value);
  87. return !isNaN(value) && (x | 0) === x;
  88. }
  89. exports.isInt = isInt;
  90. /**
  91. * Pack an array to an Object
  92. *
  93. * @example
  94. * ```js
  95. * > packObject(['a', 'b', 'c', 'd'])
  96. * { a: 'b', c: 'd' }
  97. * ```
  98. */
  99. function packObject(array) {
  100. const result = {};
  101. const length = array.length;
  102. for (let i = 1; i < length; i += 2) {
  103. result[array[i - 1]] = array[i];
  104. }
  105. return result;
  106. }
  107. exports.packObject = packObject;
  108. /**
  109. * Return a callback with timeout
  110. */
  111. function timeout(callback, timeout) {
  112. let timer = null;
  113. const run = function () {
  114. if (timer) {
  115. clearTimeout(timer);
  116. timer = null;
  117. callback.apply(this, arguments);
  118. }
  119. };
  120. timer = setTimeout(run, timeout, new Error("timeout"));
  121. return run;
  122. }
  123. exports.timeout = timeout;
  124. /**
  125. * Convert an object to an array
  126. * @example
  127. * ```js
  128. * > convertObjectToArray({ a: '1' })
  129. * ['a', '1']
  130. * ```
  131. */
  132. function convertObjectToArray(obj) {
  133. const result = [];
  134. const keys = Object.keys(obj); // Object.entries requires node 7+
  135. for (let i = 0, l = keys.length; i < l; i++) {
  136. result.push(keys[i], obj[keys[i]]);
  137. }
  138. return result;
  139. }
  140. exports.convertObjectToArray = convertObjectToArray;
  141. /**
  142. * Convert a map to an array
  143. * @example
  144. * ```js
  145. * > convertMapToArray(new Map([[1, '2']]))
  146. * [1, '2']
  147. * ```
  148. */
  149. function convertMapToArray(map) {
  150. const result = [];
  151. let pos = 0;
  152. map.forEach(function (value, key) {
  153. result[pos] = key;
  154. result[pos + 1] = value;
  155. pos += 2;
  156. });
  157. return result;
  158. }
  159. exports.convertMapToArray = convertMapToArray;
  160. /**
  161. * Convert a non-string arg to a string
  162. */
  163. function toArg(arg) {
  164. if (arg === null || typeof arg === "undefined") {
  165. return "";
  166. }
  167. return String(arg);
  168. }
  169. exports.toArg = toArg;
  170. /**
  171. * Optimize error stack
  172. *
  173. * @param error actually error
  174. * @param friendlyStack the stack that more meaningful
  175. * @param filterPath only show stacks with the specified path
  176. */
  177. function optimizeErrorStack(error, friendlyStack, filterPath) {
  178. const stacks = friendlyStack.split("\n");
  179. let lines = "";
  180. let i;
  181. for (i = 1; i < stacks.length; ++i) {
  182. if (stacks[i].indexOf(filterPath) === -1) {
  183. break;
  184. }
  185. }
  186. for (let j = i; j < stacks.length; ++j) {
  187. lines += "\n" + stacks[j];
  188. }
  189. const pos = error.stack.indexOf("\n");
  190. error.stack = error.stack.slice(0, pos) + lines;
  191. return error;
  192. }
  193. exports.optimizeErrorStack = optimizeErrorStack;
  194. /**
  195. * Parse the redis protocol url
  196. */
  197. function parseURL(url) {
  198. if (isInt(url)) {
  199. return { port: url };
  200. }
  201. let parsed = (0, url_1.parse)(url, true, true);
  202. if (!parsed.slashes && url[0] !== "/") {
  203. url = "//" + url;
  204. parsed = (0, url_1.parse)(url, true, true);
  205. }
  206. const options = parsed.query || {};
  207. const result = {};
  208. if (parsed.auth) {
  209. const index = parsed.auth.indexOf(":");
  210. result.username = index === -1 ? parsed.auth : parsed.auth.slice(0, index);
  211. result.password = index === -1 ? "" : parsed.auth.slice(index + 1);
  212. }
  213. if (parsed.pathname) {
  214. if (parsed.protocol === "redis:" || parsed.protocol === "rediss:") {
  215. if (parsed.pathname.length > 1) {
  216. result.db = parsed.pathname.slice(1);
  217. }
  218. }
  219. else {
  220. result.path = parsed.pathname;
  221. }
  222. }
  223. if (parsed.host) {
  224. result.host = parsed.hostname;
  225. }
  226. if (parsed.port) {
  227. result.port = parsed.port;
  228. }
  229. (0, lodash_1.defaults)(result, options);
  230. return result;
  231. }
  232. exports.parseURL = parseURL;
  233. /**
  234. * Resolve TLS profile shortcut in connection options
  235. */
  236. function resolveTLSProfile(options) {
  237. let tls = options === null || options === void 0 ? void 0 : options.tls;
  238. if (typeof tls === "string")
  239. tls = { profile: tls };
  240. const profile = TLSProfiles_1.default[tls === null || tls === void 0 ? void 0 : tls.profile];
  241. if (profile) {
  242. tls = Object.assign({}, profile, tls);
  243. delete tls.profile;
  244. options = Object.assign({}, options, { tls });
  245. }
  246. return options;
  247. }
  248. exports.resolveTLSProfile = resolveTLSProfile;
  249. /**
  250. * Get a random element from `array`
  251. */
  252. function sample(array, from = 0) {
  253. const length = array.length;
  254. if (from >= length) {
  255. return;
  256. }
  257. return array[from + Math.floor(Math.random() * (length - from))];
  258. }
  259. exports.sample = sample;
  260. /**
  261. * Shuffle the array using the Fisher-Yates Shuffle.
  262. * This method will mutate the original array.
  263. */
  264. function shuffle(array) {
  265. let counter = array.length;
  266. // While there are elements in the array
  267. while (counter > 0) {
  268. // Pick a random index
  269. const index = Math.floor(Math.random() * counter);
  270. // Decrease counter by 1
  271. counter--;
  272. // And swap the last element with it
  273. [array[counter], array[index]] = [array[index], array[counter]];
  274. }
  275. return array;
  276. }
  277. exports.shuffle = shuffle;
  278. /**
  279. * Error message for connection being disconnected
  280. */
  281. exports.CONNECTION_CLOSED_ERROR_MSG = "Connection is closed.";
  282. function zipMap(keys, values) {
  283. const map = new Map();
  284. keys.forEach((key, index) => {
  285. map.set(key, values[index]);
  286. });
  287. return map;
  288. }
  289. exports.zipMap = zipMap;