UNPKG

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