UNPKG

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