utils.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  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. const [isReadableStream, isRequest, isResponse, isHeaders] = ['ReadableStream', 'Request', 'Response', 'Headers'].map(kindOfTest);
  186. /**
  187. * Trim excess whitespace off the beginning and end of a string
  188. *
  189. * @param {String} str The String to trim
  190. *
  191. * @returns {String} The String freed of excess whitespace
  192. */
  193. const trim = (str) => str.trim ?
  194. str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
  195. /**
  196. * Iterate over an Array or an Object invoking a function for each item.
  197. *
  198. * If `obj` is an Array callback will be called passing
  199. * the value, index, and complete array for each item.
  200. *
  201. * If 'obj' is an Object callback will be called passing
  202. * the value, key, and complete object for each property.
  203. *
  204. * @param {Object|Array} obj The object to iterate
  205. * @param {Function} fn The callback to invoke for each item
  206. *
  207. * @param {Boolean} [allOwnKeys = false]
  208. * @returns {any}
  209. */
  210. function forEach(obj, fn, {allOwnKeys = false} = {}) {
  211. // Don't bother if no value provided
  212. if (obj === null || typeof obj === 'undefined') {
  213. return;
  214. }
  215. let i;
  216. let l;
  217. // Force an array if not already something iterable
  218. if (typeof obj !== 'object') {
  219. /*eslint no-param-reassign:0*/
  220. obj = [obj];
  221. }
  222. if (isArray(obj)) {
  223. // Iterate over array values
  224. for (i = 0, l = obj.length; i < l; i++) {
  225. fn.call(null, obj[i], i, obj);
  226. }
  227. } else {
  228. // Iterate over object keys
  229. const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);
  230. const len = keys.length;
  231. let key;
  232. for (i = 0; i < len; i++) {
  233. key = keys[i];
  234. fn.call(null, obj[key], key, obj);
  235. }
  236. }
  237. }
  238. function findKey(obj, key) {
  239. key = key.toLowerCase();
  240. const keys = Object.keys(obj);
  241. let i = keys.length;
  242. let _key;
  243. while (i-- > 0) {
  244. _key = keys[i];
  245. if (key === _key.toLowerCase()) {
  246. return _key;
  247. }
  248. }
  249. return null;
  250. }
  251. const _global = (() => {
  252. /*eslint no-undef:0*/
  253. if (typeof globalThis !== "undefined") return globalThis;
  254. return typeof self !== "undefined" ? self : (typeof window !== 'undefined' ? window : global)
  255. })();
  256. const isContextDefined = (context) => !isUndefined(context) && context !== _global;
  257. /**
  258. * Accepts varargs expecting each argument to be an object, then
  259. * immutably merges the properties of each object and returns result.
  260. *
  261. * When multiple objects contain the same key the later object in
  262. * the arguments list will take precedence.
  263. *
  264. * Example:
  265. *
  266. * ```js
  267. * var result = merge({foo: 123}, {foo: 456});
  268. * console.log(result.foo); // outputs 456
  269. * ```
  270. *
  271. * @param {Object} obj1 Object to merge
  272. *
  273. * @returns {Object} Result of all merge properties
  274. */
  275. function merge(/* obj1, obj2, obj3, ... */) {
  276. const {caseless} = isContextDefined(this) && this || {};
  277. const result = {};
  278. const assignValue = (val, key) => {
  279. const targetKey = caseless && findKey(result, key) || key;
  280. if (isPlainObject(result[targetKey]) && isPlainObject(val)) {
  281. result[targetKey] = merge(result[targetKey], val);
  282. } else if (isPlainObject(val)) {
  283. result[targetKey] = merge({}, val);
  284. } else if (isArray(val)) {
  285. result[targetKey] = val.slice();
  286. } else {
  287. result[targetKey] = val;
  288. }
  289. }
  290. for (let i = 0, l = arguments.length; i < l; i++) {
  291. arguments[i] && forEach(arguments[i], assignValue);
  292. }
  293. return result;
  294. }
  295. /**
  296. * Extends object a by mutably adding to it the properties of object b.
  297. *
  298. * @param {Object} a The object to be extended
  299. * @param {Object} b The object to copy properties from
  300. * @param {Object} thisArg The object to bind function to
  301. *
  302. * @param {Boolean} [allOwnKeys]
  303. * @returns {Object} The resulting value of object a
  304. */
  305. const extend = (a, b, thisArg, {allOwnKeys}= {}) => {
  306. forEach(b, (val, key) => {
  307. if (thisArg && isFunction(val)) {
  308. a[key] = bind(val, thisArg);
  309. } else {
  310. a[key] = val;
  311. }
  312. }, {allOwnKeys});
  313. return a;
  314. }
  315. /**
  316. * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
  317. *
  318. * @param {string} content with BOM
  319. *
  320. * @returns {string} content value without BOM
  321. */
  322. const stripBOM = (content) => {
  323. if (content.charCodeAt(0) === 0xFEFF) {
  324. content = content.slice(1);
  325. }
  326. return content;
  327. }
  328. /**
  329. * Inherit the prototype methods from one constructor into another
  330. * @param {function} constructor
  331. * @param {function} superConstructor
  332. * @param {object} [props]
  333. * @param {object} [descriptors]
  334. *
  335. * @returns {void}
  336. */
  337. const inherits = (constructor, superConstructor, props, descriptors) => {
  338. constructor.prototype = Object.create(superConstructor.prototype, descriptors);
  339. constructor.prototype.constructor = constructor;
  340. Object.defineProperty(constructor, 'super', {
  341. value: superConstructor.prototype
  342. });
  343. props && Object.assign(constructor.prototype, props);
  344. }
  345. /**
  346. * Resolve object with deep prototype chain to a flat object
  347. * @param {Object} sourceObj source object
  348. * @param {Object} [destObj]
  349. * @param {Function|Boolean} [filter]
  350. * @param {Function} [propFilter]
  351. *
  352. * @returns {Object}
  353. */
  354. const toFlatObject = (sourceObj, destObj, filter, propFilter) => {
  355. let props;
  356. let i;
  357. let prop;
  358. const merged = {};
  359. destObj = destObj || {};
  360. // eslint-disable-next-line no-eq-null,eqeqeq
  361. if (sourceObj == null) return destObj;
  362. do {
  363. props = Object.getOwnPropertyNames(sourceObj);
  364. i = props.length;
  365. while (i-- > 0) {
  366. prop = props[i];
  367. if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {
  368. destObj[prop] = sourceObj[prop];
  369. merged[prop] = true;
  370. }
  371. }
  372. sourceObj = filter !== false && getPrototypeOf(sourceObj);
  373. } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);
  374. return destObj;
  375. }
  376. /**
  377. * Determines whether a string ends with the characters of a specified string
  378. *
  379. * @param {String} str
  380. * @param {String} searchString
  381. * @param {Number} [position= 0]
  382. *
  383. * @returns {boolean}
  384. */
  385. const endsWith = (str, searchString, position) => {
  386. str = String(str);
  387. if (position === undefined || position > str.length) {
  388. position = str.length;
  389. }
  390. position -= searchString.length;
  391. const lastIndex = str.indexOf(searchString, position);
  392. return lastIndex !== -1 && lastIndex === position;
  393. }
  394. /**
  395. * Returns new array from array like object or null if failed
  396. *
  397. * @param {*} [thing]
  398. *
  399. * @returns {?Array}
  400. */
  401. const toArray = (thing) => {
  402. if (!thing) return null;
  403. if (isArray(thing)) return thing;
  404. let i = thing.length;
  405. if (!isNumber(i)) return null;
  406. const arr = new Array(i);
  407. while (i-- > 0) {
  408. arr[i] = thing[i];
  409. }
  410. return arr;
  411. }
  412. /**
  413. * Checking if the Uint8Array exists and if it does, it returns a function that checks if the
  414. * thing passed in is an instance of Uint8Array
  415. *
  416. * @param {TypedArray}
  417. *
  418. * @returns {Array}
  419. */
  420. // eslint-disable-next-line func-names
  421. const isTypedArray = (TypedArray => {
  422. // eslint-disable-next-line func-names
  423. return thing => {
  424. return TypedArray && thing instanceof TypedArray;
  425. };
  426. })(typeof Uint8Array !== 'undefined' && getPrototypeOf(Uint8Array));
  427. /**
  428. * For each entry in the object, call the function with the key and value.
  429. *
  430. * @param {Object<any, any>} obj - The object to iterate over.
  431. * @param {Function} fn - The function to call for each entry.
  432. *
  433. * @returns {void}
  434. */
  435. const forEachEntry = (obj, fn) => {
  436. const generator = obj && obj[Symbol.iterator];
  437. const iterator = generator.call(obj);
  438. let result;
  439. while ((result = iterator.next()) && !result.done) {
  440. const pair = result.value;
  441. fn.call(obj, pair[0], pair[1]);
  442. }
  443. }
  444. /**
  445. * It takes a regular expression and a string, and returns an array of all the matches
  446. *
  447. * @param {string} regExp - The regular expression to match against.
  448. * @param {string} str - The string to search.
  449. *
  450. * @returns {Array<boolean>}
  451. */
  452. const matchAll = (regExp, str) => {
  453. let matches;
  454. const arr = [];
  455. while ((matches = regExp.exec(str)) !== null) {
  456. arr.push(matches);
  457. }
  458. return arr;
  459. }
  460. /* Checking if the kindOfTest function returns true when passed an HTMLFormElement. */
  461. const isHTMLForm = kindOfTest('HTMLFormElement');
  462. const toCamelCase = str => {
  463. return str.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g,
  464. function replacer(m, p1, p2) {
  465. return p1.toUpperCase() + p2;
  466. }
  467. );
  468. };
  469. /* Creating a function that will check if an object has a property. */
  470. const hasOwnProperty = (({hasOwnProperty}) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype);
  471. /**
  472. * Determine if a value is a RegExp object
  473. *
  474. * @param {*} val The value to test
  475. *
  476. * @returns {boolean} True if value is a RegExp object, otherwise false
  477. */
  478. const isRegExp = kindOfTest('RegExp');
  479. const reduceDescriptors = (obj, reducer) => {
  480. const descriptors = Object.getOwnPropertyDescriptors(obj);
  481. const reducedDescriptors = {};
  482. forEach(descriptors, (descriptor, name) => {
  483. let ret;
  484. if ((ret = reducer(descriptor, name, obj)) !== false) {
  485. reducedDescriptors[name] = ret || descriptor;
  486. }
  487. });
  488. Object.defineProperties(obj, reducedDescriptors);
  489. }
  490. /**
  491. * Makes all methods read-only
  492. * @param {Object} obj
  493. */
  494. const freezeMethods = (obj) => {
  495. reduceDescriptors(obj, (descriptor, name) => {
  496. // skip restricted props in strict mode
  497. if (isFunction(obj) && ['arguments', 'caller', 'callee'].indexOf(name) !== -1) {
  498. return false;
  499. }
  500. const value = obj[name];
  501. if (!isFunction(value)) return;
  502. descriptor.enumerable = false;
  503. if ('writable' in descriptor) {
  504. descriptor.writable = false;
  505. return;
  506. }
  507. if (!descriptor.set) {
  508. descriptor.set = () => {
  509. throw Error('Can not rewrite read-only method \'' + name + '\'');
  510. };
  511. }
  512. });
  513. }
  514. const toObjectSet = (arrayOrString, delimiter) => {
  515. const obj = {};
  516. const define = (arr) => {
  517. arr.forEach(value => {
  518. obj[value] = true;
  519. });
  520. }
  521. isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter));
  522. return obj;
  523. }
  524. const noop = () => {}
  525. const toFiniteNumber = (value, defaultValue) => {
  526. return value != null && Number.isFinite(value = +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. // original code
  579. // https://github.com/DigitalBrainJS/AxiosPromise/blob/16deab13710ec09779922131f3fa5954320f83ab/lib/utils.js#L11-L34
  580. const _setImmediate = ((setImmediateSupported, postMessageSupported) => {
  581. if (setImmediateSupported) {
  582. return setImmediate;
  583. }
  584. return postMessageSupported ? ((token, callbacks) => {
  585. _global.addEventListener("message", ({source, data}) => {
  586. if (source === _global && data === token) {
  587. callbacks.length && callbacks.shift()();
  588. }
  589. }, false);
  590. return (cb) => {
  591. callbacks.push(cb);
  592. _global.postMessage(token, "*");
  593. }
  594. })(`axios@${Math.random()}`, []) : (cb) => setTimeout(cb);
  595. })(
  596. typeof setImmediate === 'function',
  597. isFunction(_global.postMessage)
  598. );
  599. const asap = typeof queueMicrotask !== 'undefined' ?
  600. queueMicrotask.bind(_global) : ( typeof process !== 'undefined' && process.nextTick || _setImmediate);
  601. // *********************
  602. export default {
  603. isArray,
  604. isArrayBuffer,
  605. isBuffer,
  606. isFormData,
  607. isArrayBufferView,
  608. isString,
  609. isNumber,
  610. isBoolean,
  611. isObject,
  612. isPlainObject,
  613. isReadableStream,
  614. isRequest,
  615. isResponse,
  616. isHeaders,
  617. isUndefined,
  618. isDate,
  619. isFile,
  620. isBlob,
  621. isRegExp,
  622. isFunction,
  623. isStream,
  624. isURLSearchParams,
  625. isTypedArray,
  626. isFileList,
  627. forEach,
  628. merge,
  629. extend,
  630. trim,
  631. stripBOM,
  632. inherits,
  633. toFlatObject,
  634. kindOf,
  635. kindOfTest,
  636. endsWith,
  637. toArray,
  638. forEachEntry,
  639. matchAll,
  640. isHTMLForm,
  641. hasOwnProperty,
  642. hasOwnProp: hasOwnProperty, // an alias to avoid ESLint no-prototype-builtins detection
  643. reduceDescriptors,
  644. freezeMethods,
  645. toObjectSet,
  646. toCamelCase,
  647. noop,
  648. toFiniteNumber,
  649. findKey,
  650. global: _global,
  651. isContextDefined,
  652. ALPHABET,
  653. generateString,
  654. isSpecCompliantForm,
  655. toJSONObject,
  656. isAsyncFn,
  657. isThenable,
  658. setImmediate: _setImmediate,
  659. asap
  660. };