223 lines
4.9 KiB
JavaScript
223 lines
4.9 KiB
JavaScript
|
|
/**
|
||
|
|
* Collection utilities - ES Module Version
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { typeOf, isObject, isArray, isString, isFunction } from './Type.js';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Iterate over collections
|
||
|
|
*/
|
||
|
|
export function forEach(collection, iterator, that) {
|
||
|
|
const type = typeOf(collection);
|
||
|
|
let i, key;
|
||
|
|
|
||
|
|
if (type === 'object') {
|
||
|
|
for (key in collection) {
|
||
|
|
if (collection.hasOwnProperty(key)) {
|
||
|
|
if (iterator.call(that, collection[key], key, collection) === false) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else if (type === 'array' || type === 'string') {
|
||
|
|
for (i = 0; i < collection.length; i++) {
|
||
|
|
if (iterator.call(that, collection[i], i, collection) === false) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return collection;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get length of collection
|
||
|
|
*/
|
||
|
|
export function len(collection) {
|
||
|
|
const type = typeOf(collection);
|
||
|
|
|
||
|
|
if (type === 'array' || type === 'string') {
|
||
|
|
return collection.length;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (type === 'object') {
|
||
|
|
return Object.keys(collection).length;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extend objects (similar to Object.assign but deeper)
|
||
|
|
*/
|
||
|
|
export function extend(...args) {
|
||
|
|
let target = args[0] || {};
|
||
|
|
let deep = false;
|
||
|
|
let i = 1;
|
||
|
|
|
||
|
|
// Check if deep copy
|
||
|
|
if (typeof target === 'boolean') {
|
||
|
|
deep = target;
|
||
|
|
target = args[1] || {};
|
||
|
|
i = 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (; i < args.length; i++) {
|
||
|
|
const source = args[i];
|
||
|
|
if (!source) continue;
|
||
|
|
|
||
|
|
for (const key in source) {
|
||
|
|
if (source.hasOwnProperty(key)) {
|
||
|
|
const src = target[key];
|
||
|
|
const copy = source[key];
|
||
|
|
|
||
|
|
// Prevent infinite loop
|
||
|
|
if (target === copy) continue;
|
||
|
|
|
||
|
|
if (deep && copy && (isObject(copy) || isArray(copy))) {
|
||
|
|
let clone;
|
||
|
|
if (isArray(copy)) {
|
||
|
|
clone = src && isArray(src) ? src : [];
|
||
|
|
} else {
|
||
|
|
clone = src && isObject(src) ? src : {};
|
||
|
|
}
|
||
|
|
target[key] = extend(deep, clone, copy);
|
||
|
|
} else if (copy !== undefined) {
|
||
|
|
target[key] = copy;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return target;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Map over collections
|
||
|
|
*/
|
||
|
|
export function map(collection, iterator, that) {
|
||
|
|
const type = typeOf(collection);
|
||
|
|
const result = [];
|
||
|
|
|
||
|
|
forEach(collection, function(value, key) {
|
||
|
|
result.push(iterator.call(that, value, key, collection));
|
||
|
|
});
|
||
|
|
|
||
|
|
return type === 'string' ? result.join('') : result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filter collections
|
||
|
|
*/
|
||
|
|
export function filter(collection, iterator, that) {
|
||
|
|
const type = typeOf(collection);
|
||
|
|
const result = type === 'object' ? {} : [];
|
||
|
|
|
||
|
|
forEach(collection, function(value, key) {
|
||
|
|
if (iterator.call(that, value, key, collection)) {
|
||
|
|
if (type === 'object') {
|
||
|
|
result[key] = value;
|
||
|
|
} else {
|
||
|
|
result.push(value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
return type === 'string' ? result.join('') : result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Find in collection
|
||
|
|
*/
|
||
|
|
export function find(collection, iterator, that) {
|
||
|
|
let result;
|
||
|
|
|
||
|
|
forEach(collection, function(value, key) {
|
||
|
|
if (iterator.call(that, value, key, collection)) {
|
||
|
|
result = value;
|
||
|
|
return false; // break
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if every element passes test
|
||
|
|
*/
|
||
|
|
export function every(collection, iterator, that) {
|
||
|
|
let result = true;
|
||
|
|
|
||
|
|
forEach(collection, function(value, key) {
|
||
|
|
if (!iterator.call(that, value, key, collection)) {
|
||
|
|
result = false;
|
||
|
|
return false; // break
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check if any element passes test
|
||
|
|
*/
|
||
|
|
export function some(collection, iterator, that) {
|
||
|
|
let result = false;
|
||
|
|
|
||
|
|
forEach(collection, function(value, key) {
|
||
|
|
if (iterator.call(that, value, key, collection)) {
|
||
|
|
result = true;
|
||
|
|
return false; // break
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get keys of object or indices of array
|
||
|
|
*/
|
||
|
|
export function keys(collection) {
|
||
|
|
if (isObject(collection)) {
|
||
|
|
return Object.keys(collection);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (isArray(collection) || isString(collection)) {
|
||
|
|
return Array.from({ length: collection.length }, (_, i) => i);
|
||
|
|
}
|
||
|
|
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get values of collection
|
||
|
|
*/
|
||
|
|
export function values(collection) {
|
||
|
|
if (isObject(collection)) {
|
||
|
|
return Object.values(collection);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (isArray(collection)) {
|
||
|
|
return [...collection];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (isString(collection)) {
|
||
|
|
return collection.split('');
|
||
|
|
}
|
||
|
|
|
||
|
|
return [];
|
||
|
|
}
|
||
|
|
|
||
|
|
// Export all functions
|
||
|
|
export default {
|
||
|
|
forEach,
|
||
|
|
len,
|
||
|
|
extend,
|
||
|
|
map,
|
||
|
|
filter,
|
||
|
|
find,
|
||
|
|
every,
|
||
|
|
some,
|
||
|
|
keys,
|
||
|
|
values
|
||
|
|
};
|