utils.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. 'use strict';
  2. import bind from './helpers/bind.js';
  3. // utils is a library of generic helper functions non-specific to axios
  4. const {toString} = Object.prototype;
  5. const {getPrototypeOf} = Object;
  6. const kindOf = (cache => thing => {
  7. const str = toString.call(thing);
  8. return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
  9. })(Object.create(null));
  10. const kindOfTest = (type) => {
  11. type = type.toLowerCase();
  12. return (thing) => kindOf(thing) === type
  13. }
  14. const typeOfTest = type => thing => typeof thing === type;
  15. /**
  16. * Determine if a value is an Array
  17. *
  18. * @param {Object} val The value to test
  19. *
  20. * @returns {boolean} True if value is an Array, otherwise false
  21. */
  22. const {isArray} = Array;
  23. /**
  24. * Determine if a value is undefined
  25. *
  26. * @param {*} val The value to test
  27. *
  28. * @returns {boolean} True if the value is undefined, otherwise false
  29. */
  30. const isUndefined = typeOfTest('undefined');
  31. /**
  32. * Determine if a value is a Buffer
  33. *
  34. * @param {*} val The value to test
  35. *
  36. * @returns {boolean} True if value is a Buffer, otherwise false
  37. */
  38. function isBuffer(val) {
  39. return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
  40. && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val);
  41. }
  42. /**
  43. * Determine if a value is an ArrayBuffer
  44. *
  45. * @param {*} val The value to test
  46. *
  47. * @returns {boolean} True if value is an ArrayBuffer, otherwise false
  48. */
  49. const isArrayBuffer = kindOfTest('ArrayBuffer');
  50. /**
  51. * Determine if a value is a view on an ArrayBuffer
  52. *
  53. * @param {*} val The value to test
  54. *
  55. * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
  56. */
  57. function isArrayBufferView(val) {
  58. let result;
  59. if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
  60. result = ArrayBuffer.isView(val);
  61. } else {
  62. result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));
  63. }
  64. return result;
  65. }
  66. /**
  67. * Determine if a value is a String
  68. *
  69. * @param {*} val The value to test
  70. *
  71. * @returns {boolean} True if value is a String, otherwise false
  72. */
  73. const isString = typeOfTest('string');
  74. /**
  75. * Determine if a value is a Function
  76. *
  77. * @param {*} val The value to test
  78. * @returns {boolean} True if value is a Function, otherwise false
  79. */
  80. const isFunction = typeOfTest('function');
  81. /**
  82. * Determine if a value is a Number
  83. *
  84. * @param {*} val The value to test
  85. *
  86. * @returns {boolean} True if value is a Number, otherwise false
  87. */
  88. const isNumber = typeOfTest('number');
  89. /**
  90. * Determine if a value is an Object
  91. *
  92. * @param {*} thing The value to test
  93. *
  94. * @returns {boolean} True if value is an Object, otherwise false
  95. */
  96. const isObject = (thing) => thing !== null && typeof thing === 'object';
  97. /**
  98. * Determine if a value is a Boolean
  99. *
  100. * @param {*} thing The value to test
  101. * @returns {boolean} True if value is a Boolean, otherwise false
  102. */
  103. const isBoolean = thing => thing === true || thing === false;
  104. /**
  105. * Determine if a value is a plain Object
  106. *
  107. * @param {*} val The value to test
  108. *
  109. * @returns {boolean} True if value is a plain Object, otherwise false
  110. */
  111. const isPlainObject = (val) => {
  112. if (kindOf(val) !== 'object') {
  113. return false;
  114. }
  115. const prototype = getPrototypeOf(val);
  116. return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val);
  117. }
  118. /**
  119. * Determine if a value is a Date
  120. *
  121. * @param {*} val The value to test
  122. *
  123. * @returns {boolean} True if value is a Date, otherwise false
  124. */
  125. const isDate = kindOfTest('Date');
  126. /**
  127. * Determine if a value is a File
  128. *
  129. * @param {*} val The value to test
  130. *
  131. * @returns {boolean} True if value is a File, otherwise false
  132. */
  133. const isFile = kindOfTest('File');
  134. /**
  135. * Determine if a value is a Blob
  136. *
  137. * @param {*} val The value to test
  138. *
  139. * @returns {boolean} True if value is a Blob, otherwise false
  140. */
  141. const isBlob = kindOfTest('Blob');
  142. /**
  143. * Determine if a value is a FileList
  144. *
  145. * @param {*} val The value to test
  146. *
  147. * @returns {boolean} True if value is a File, otherwise false
  148. */
  149. const isFileList = kindOfTest('FileList');
  150. /**
  151. * Determine if a value is a Stream
  152. *
  153. * @param {*} val The value to test
  154. *
  155. * @returns {boolean} True if value is a Stream, otherwise false
  156. */
  157. const isStream = (val) => isObject(val) && isFunction(val.pipe);
  158. /**
  159. * Determine if a value is a FormData
  160. *
  161. * @param {*} thing The value to test
  162. *
  163. * @returns {boolean} True if value is an FormData, otherwise false
  164. */
  165. const isFormData = (thing) => {
  166. let kind;
  167. return thing && (
  168. (typeof FormData === 'function' && thing instanceof FormData) || (
  169. isFunction(thing.append) && (
  170. (kind = kindOf(thing)) === 'formdata' ||
  171. // detect form-data instance
  172. (kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]')
  173. )
  174. )
  175. )
  176. }
  177. /**
  178. * Determine if a value is a URLSearchParams object
  179. *
  180. * @param {*} val The value to test
  181. *
  182. * @returns {boolean} True if value is a URLSearchParams object, otherwise false
  183. */
  184. const isURLSearchParams = kindOfTest('URLSearchParams');
  185. /**
  186. * Trim excess whitespace off the beginning and end of a string
  187. *
  188. * @param {String} str The String to trim
  189. *
  190. * @returns {String} The String freed of excess whitespace
  191. */
  192. const trim = (str) => str.trim ?
  193. str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
  194. /**
  195. * Iterate over an Array or an Object invoking a function for each item.
  196. *
  197. * If `obj` is an Array callback will be called passing
  198. * the value, index, and complete array for each item.
  199. *
  200. * If 'obj' is an Object callback will be called passing
  201. * the value, key, and complete object for each property.
  202. *
  203. * @param {Object|Array} obj The object to iterate
  204. * @param {Function} fn The callback to invoke for each item
  205. *
  206. * @param {Boolean} [allOwnKeys = false]
  207. * @returns {any}
  208. */
  209. function forEach(obj, fn, {allOwnKeys = false} = {}) {
  210. // Don't bother if no value provided
  211. if (obj === null || typeof obj === 'undefined') {
  212. return;
  213. }
  214. let i;
  215. let l;
  216. // Force an array if not already something iterable
  217. if (typeof obj !== 'object') {
  218. /*eslint no-param-reassign:0*/
  219. obj = [obj];
  220. }
  221. if (isArray(obj)) {
  222. // Iterate over array values
  223. for (i = 0, l = obj.length; i < l; i++) {
  224. fn.call(null, obj[i], i, obj);
  225. }
  226. } else {
  227. // Iterate over object keys
  228. const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);
  229. const len = keys.length;
  230. let key;
  231. for (i = 0; i < len; i++) {
  232. key = keys[i];
  233. fn.call(null, obj[key], key, obj);
  234. }
  235. }
  236. }
  237. function findKey(obj, key) {
  238. key = key.toLowerCase();
  239. const keys = Object.keys(obj);
  240. let i = keys.length;
  241. let _key;
  242. while (i-- > 0) {
  243. _key = keys[i];
  244. if (key === _key.toLowerCase()) {
  245. return _key;
  246. }
  247. }
  248. return null;
  249. }
  250. const _global = (() => {
  251. /*eslint no-undef:0*/
  252. if (typeof globalThis !== "undefined") return globalThis;
  253. return typeof self !== "undefined" ? self : (typeof window !== 'undefined' ? window : global)
  254. })();
  255. const isContextDefined = (context) => !isUndefined(context) && context !== _global;
  256. /**
  257. * Accepts varargs expecting each argument to be an object, then
  258. * immutably merges the properties of each object and returns result.
  259. *
  260. * When multiple objects contain the same key the later object in
  261. * the arguments list will take precedence.
  262. *
  263. * Example:
  264. *
  265. * ```js
  266. * var result = merge({foo: 123}, {foo: 456});
  267. * console.log(result.foo); // outputs 456
  268. * ```
  269. *
  270. * @param {Object} obj1 Object to merge
  271. *
  272. * @returns {Object} Result of all merge properties
  273. */
  274. function merge(/* obj1, obj2, obj3, ... */) {
  275. const {caseless} = isContextDefined(this) && this || {};
  276. const result = {};
  277. const assignValue = (val, key) => {
  278. const targetKey = caseless && findKey(result, key) || key;
  279. if (isPlainObject(result[targetKey]) && isPlainObject(val)) {
  280. result[targetKey] = merge(result[targetKey], val);
  281. } else if (isPlainObject(val)) {
  282. result[targetKey] = merge({}, val);
  283. } else if (isArray(val)) {
  284. result[targetKey] = val.slice();
  285. } else {
  286. result[targetKey] = val;
  287. }
  288. }
  289. for (let i = 0, l = arguments.length; i < l; i++) {
  290. arguments[i] && forEach(arguments[i], assignValue);
  291. }
  292. return result;
  293. }
  294. /**
  295. * Extends object a by mutably adding to it the properties of object b.
  296. *
  297. * @param {Object} a The object to be extended
  298. * @param {Object} b The object to copy properties from
  299. * @param {Object} thisArg The object to bind function to
  300. *
  301. * @param {Boolean} [allOwnKeys]
  302. * @returns {Object} The resulting value of object a
  303. */
  304. const extend = (a, b, thisArg, {allOwnKeys}= {}) => {
  305. forEach(b, (val, key) => {
  306. if (thisArg && isFunction(val)) {
  307. a[key] = bind(val, thisArg);
  308. } else {
  309. a[key] = val;
  310. }
  311. }, {allOwnKeys});
  312. return a;
  313. }
  314. /**
  315. * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
  316. *
  317. * @param {string} content with BOM
  318. *
  319. * @returns {string} content value without BOM
  320. */
  321. const stripBOM = (content) => {
  322. if (content.charCodeAt(0) === 0xFEFF) {
  323. content = content.slice(1);
  324. }
  325. return content;
  326. }
  327. /**
  328. * Inherit the prototype methods from one constructor into another
  329. * @param {function} constructor
  330. * @param {function} superConstructor
  331. * @param {object} [props]
  332. * @param {object} [descriptors]
  333. *
  334. * @returns {void}
  335. */
  336. const inherits = (constructor, superConstructor, props, descriptors) => {
  337. constructor.prototype = Object.create(superConstructor.prototype, descriptors);
  338. constructor.prototype.constructor = constructor;
  339. Object.defineProperty(constructor, 'super', {
  340. value: superConstructor.prototype
  341. });
  342. props && Object.assign(constructor.prototype, props);
  343. }
  344. /**
  345. * Resolve object with deep prototype chain to a flat object
  346. * @param {Object} sourceObj source object
  347. * @param {Object} [destObj]
  348. * @param {Function|Boolean} [filter]
  349. * @param {Function} [propFilter]
  350. *
  351. * @returns {Object}
  352. */
  353. const toFlatObject = (sourceObj, destObj, filter, propFilter) => {
  354. let props;
  355. let i;
  356. let prop;
  357. const merged = {};
  358. destObj = destObj || {};
  359. // eslint-disable-next-line no-eq-null,eqeqeq
  360. if (sourceObj == null) return destObj;
  361. do {
  362. props = Object.getOwnPropertyNames(sourceObj);
  363. i = props.length;
  364. while (i-- > 0) {
  365. prop = props[i];
  366. if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {
  367. destObj[prop] = sourceObj[prop];
  368. merged[prop] = true;
  369. }
  370. }
  371. sourceObj = filter !== false && getPrototypeOf(sourceObj);
  372. } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);
  373. return destObj;
  374. }
  375. /**
  376. * Determines whether a string ends with the characters of a specified string
  377. *
  378. * @param {String} str
  379. * @param {String} searchString
  380. * @param {Number} [position= 0]
  381. *
  382. * @returns {boolean}
  383. */
  384. const endsWith = (str, searchString, position) => {
  385. str = String(str);
  386. if (position === undefined || position > str.length) {
  387. position = str.length;
  388. }
  389. position -= searchString.length;
  390. const lastIndex = str.indexOf(searchString, position);
  391. return lastIndex !== -1 && lastIndex === position;
  392. }
  393. /**
  394. * Returns new array from array like object or null if failed
  395. *
  396. * @param {*} [thing]
  397. *
  398. * @returns {?Array}
  399. */
  400. const toArray = (thing) => {
  401. if (!thing) return null;
  402. if (isArray(thing)) return thing;
  403. let i = thing.length;
  404. if (!isNumber(i)) return null;
  405. const arr = new Array(i);
  406. while (i-- > 0) {
  407. arr[i] = thing[i];
  408. }
  409. return arr;
  410. }
  411. /**
  412. * Checking if the Uint8Array exists and if it does, it returns a function that checks if the
  413. * thing passed in is an instance of Uint8Array
  414. *
  415. * @param {TypedArray}
  416. *
  417. * @returns {Array}
  418. */
  419. // eslint-disable-next-line func-names
  420. const isTypedArray = (TypedArray => {
  421. // eslint-disable-next-line func-names
  422. return thing => {
  423. return TypedArray && thing instanceof TypedArray;
  424. };
  425. })(typeof Uint8Array !== 'undefined' && getPrototypeOf(Uint8Array));
  426. /**
  427. * For each entry in the object, call the function with the key and value.
  428. *
  429. * @param {Object<any, any>} obj - The object to iterate over.
  430. * @param {Function} fn - The function to call for each entry.
  431. *
  432. * @returns {void}
  433. */
  434. const forEachEntry = (obj, fn) => {
  435. const generator = obj && obj[Symbol.iterator];
  436. const iterator = generator.call(obj);
  437. let result;
  438. while ((result = iterator.next()) && !result.done) {
  439. const pair = result.value;
  440. fn.call(obj, pair[0], pair[1]);
  441. }
  442. }
  443. /**
  444. * It takes a regular expression and a string, and returns an array of all the matches
  445. *
  446. * @param {string} regExp - The regular expression to match against.
  447. * @param {string} str - The string to search.
  448. *
  449. * @returns {Array<boolean>}
  450. */
  451. const matchAll = (regExp, str) => {
  452. let matches;
  453. const arr = [];
  454. while ((matches = regExp.exec(str)) !== null) {
  455. arr.push(matches);
  456. }
  457. return arr;
  458. }
  459. /* Checking if the kindOfTest function returns true when passed an HTMLFormElement. */
  460. const isHTMLForm = kindOfTest('HTMLFormElement');
  461. const toCamelCase = str => {
  462. return str.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,
  463. function replacer(m, p1, p2) {
  464. return p1.toUpperCase() + p2;
  465. }
  466. );
  467. };
  468. /* Creating a function that will check if an object has a property. */
  469. const hasOwnProperty = (({hasOwnProperty}) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype);
  470. /**
  471. * Determine if a value is a RegExp object
  472. *
  473. * @param {*} val The value to test
  474. *
  475. * @returns {boolean} True if value is a RegExp object, otherwise false
  476. */
  477. const isRegExp = kindOfTest('RegExp');
  478. const reduceDescriptors = (obj, reducer) => {
  479. const descriptors = Object.getOwnPropertyDescriptors(obj);
  480. const reducedDescriptors = {};
  481. forEach(descriptors, (descriptor, name) => {
  482. let ret;
  483. if ((ret = reducer(descriptor, name, obj)) !== false) {
  484. reducedDescriptors[name] = ret || descriptor;
  485. }
  486. });
  487. Object.defineProperties(obj, reducedDescriptors);
  488. }
  489. /**
  490. * Makes all methods read-only
  491. * @param {Object} obj
  492. */
  493. const freezeMethods = (obj) => {
  494. reduceDescriptors(obj, (descriptor, name) => {
  495. // skip restricted props in strict mode
  496. if (isFunction(obj) && ['arguments', 'caller', 'callee'].indexOf(name) !== -1) {
  497. return false;
  498. }
  499. const value = obj[name];
  500. if (!isFunction(value)) return;
  501. descriptor.enumerable = false;
  502. if ('writable' in descriptor) {
  503. descriptor.writable = false;
  504. return;
  505. }
  506. if (!descriptor.set) {
  507. descriptor.set = () => {
  508. throw Error('Can not rewrite read-only method \'' + name + '\'');
  509. };
  510. }
  511. });
  512. }
  513. const toObjectSet = (arrayOrString, delimiter) => {
  514. const obj = {};
  515. const define = (arr) => {
  516. arr.forEach(value => {
  517. obj[value] = true;
  518. });
  519. }
  520. isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter));
  521. return obj;
  522. }
  523. const noop = () => {}
  524. const toFiniteNumber = (value, defaultValue) => {
  525. value = +value;
  526. return Number.isFinite(value) ? value : defaultValue;
  527. }
  528. const ALPHA = 'abcdefghijklmnopqrstuvwxyz'
  529. const DIGIT = '0123456789';
  530. const ALPHABET = {
  531. DIGIT,
  532. ALPHA,
  533. ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT
  534. }
  535. const generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {
  536. let str = '';
  537. const {length} = alphabet;
  538. while (size--) {
  539. str += alphabet[Math.random() * length|0]
  540. }
  541. return str;
  542. }
  543. /**
  544. * If the thing is a FormData object, return true, otherwise return false.
  545. *
  546. * @param {unknown} thing - The thing to check.
  547. *
  548. * @returns {boolean}
  549. */
  550. function isSpecCompliantForm(thing) {
  551. return !!(thing && isFunction(thing.append) && thing[Symbol.toStringTag] === 'FormData' && thing[Symbol.iterator]);
  552. }
  553. const toJSONObject = (obj) => {
  554. const stack = new Array(10);
  555. const visit = (source, i) => {
  556. if (isObject(source)) {
  557. if (stack.indexOf(source) >= 0) {
  558. return;
  559. }
  560. if(!('toJSON' in source)) {
  561. stack[i] = source;
  562. const target = isArray(source) ? [] : {};
  563. forEach(source, (value, key) => {
  564. const reducedValue = visit(value, i + 1);
  565. !isUndefined(reducedValue) && (target[key] = reducedValue);
  566. });
  567. stack[i] = undefined;
  568. return target;
  569. }
  570. }
  571. return source;
  572. }
  573. return visit(obj, 0);
  574. }
  575. const isAsyncFn = kindOfTest('AsyncFunction');
  576. const isThenable = (thing) =>
  577. thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch);
  578. export default {
  579. isArray,
  580. isArrayBuffer,
  581. isBuffer,
  582. isFormData,
  583. isArrayBufferView,
  584. isString,
  585. isNumber,
  586. isBoolean,
  587. isObject,
  588. isPlainObject,
  589. isUndefined,
  590. isDate,
  591. isFile,
  592. isBlob,
  593. isRegExp,
  594. isFunction,
  595. isStream,
  596. isURLSearchParams,
  597. isTypedArray,
  598. isFileList,
  599. forEach,
  600. merge,
  601. extend,
  602. trim,
  603. stripBOM,
  604. inherits,
  605. toFlatObject,
  606. kindOf,
  607. kindOfTest,
  608. endsWith,
  609. toArray,
  610. forEachEntry,
  611. matchAll,
  612. isHTMLForm,
  613. hasOwnProperty,
  614. hasOwnProp: hasOwnProperty, // an alias to avoid ESLint no-prototype-builtins detection
  615. reduceDescriptors,
  616. freezeMethods,
  617. toObjectSet,
  618. toCamelCase,
  619. noop,
  620. toFiniteNumber,
  621. findKey,
  622. global: _global,
  623. isContextDefined,
  624. ALPHABET,
  625. generateString,
  626. isSpecCompliantForm,
  627. toJSONObject,
  628. isAsyncFn,
  629. isThenable
  630. };