utils.js 18 KB

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