map-plus
Version:
Creates a new array of values by mapping each value in list through an iteratee.
126 lines (91 loc) • 2.88 kB
JavaScript
const isObject = (obj) => {
const type = typeof obj;
return type === 'function' || (type === 'object' && !!obj);
};
const getKeys = (obj) => {
if (!isObject(obj)) return [];
return Object.keys(obj);
};
const shallowProperty = (key) => (obj) =>
obj == null ? undefined : obj[key];
const getLength = shallowProperty('length');
const isArrayLike = (collection) => {
const length = getLength(collection);
return typeof length === 'number' &&
length >= 0 &&
length <= Number.MAX_SAFE_INTEGER;
};
const identity = (value) => value;
const isFunction = (obj) =>
Object.prototype.toString.call(obj) === '[object Function]';
const optimizeCb = (func, context, argCount) => {
if (context === undefined) return func;
switch (argCount == null ? 3 : argCount) {
case 1:
return (value) => func.call(context, value);
// The 2-argument case is omitted because we’re not using it.
case 3:
return (value, index, collection) =>
func.call(context, value, index, collection);
case 4:
return (accumulator, value, index, collection) =>
func.call(context, accumulator, value, index, collection);
default:
return (...args) => func.apply(context, args);
}
};
const isMatch = (object, attrs) => {
const keys = getKeys(attrs);
const { length } = keys;
if (object == null) return !length;
const obj = Object(object);
for (let i = 0; i < length; i++) {
const key = keys[i];
if (attrs[key] !== obj[key] || !(key in obj)) return false;
}
return true;
};
const matcher = (attrs) => {
attrs = { ...attrs };
return (obj) => isMatch(obj, attrs);
};
const deepGet = (obj, path) => {
const { length } = path;
for (let i = 0; i < length; i++) {
if (obj == null) return undefined;
obj = obj[path[i]];
}
return length ? obj : undefined;
};
const property = (path) => {
if (!Array.isArray(path)) {
return shallowProperty(path);
}
return (obj) => deepGet(obj, path);
};
const baseIteratee = (value, context, argCount) => {
if (value == null) return identity;
if (isFunction(value)) return optimizeCb(value, context, argCount);
if (isObject(value) && !Array.isArray(value)) return matcher(value);
return property(value);
};
let iteratee;
const exportIteratee = (iteratee = (value, context) =>
baseIteratee(value, context, Infinity)
);
const cb = (value, context, argCount) => {
if (iteratee !== exportIteratee) return iteratee(value, context);
return baseIteratee(value, context, argCount);
};
const map = (obj, iteratee, context) => {
iteratee = cb(iteratee, context);
const keys = !isArrayLike(obj) && getKeys(obj);
const { length } = keys || obj;
const results = new Array(length);
for (let index = 0; index < length; index++) {
const currentKey = keys ? keys[index] : index;
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
return results;
};
module.exports = map;