export interface GenericFunction {
(a: A): B
}
export interface Hash {
[key: string]: A
};
export interface ObjectReducer {
(accum?: B, value?: A, key?: string, hash?: Hash): B
}
export interface ObjectMapper {
(value?: A, key?: string, hash?: Hash): B
}
/**
* identity is the famed identity function.
*/
export const identity = (a: A): A => a;
export interface O {
[key: string]: A
}
/**
* merge two objects easily
*/
export const merge = (...o: A[]): B =>
Object.assign.apply(Object, [{}].concat(o));
/**
* fuse is the deep version of merge
*/
export const fuse = (...args: A[]): B =>
args.reduce((o: B, c: A = ({})) =>
reduce(c, (co: B, cc: any, k: string) =>
Array.isArray(cc) ?
(Array.isArray((co)[k]) ?
merge(co, { [k]: ((co)[k]).map(copy).concat(cc.map(copy)) }) :
merge(co, { [k]: cc.map(copy) })) :
typeof cc !== 'object' ?
merge(co, { [k]: cc }) :
merge(co, {
[k]: (typeof (co)[k] !== 'object') ?
merge((co)[k], cc) :
fuse((co)[k], cc)
}), o), {})
export const copy = (o: A): B =>
(Array.isArray(o)) ?
o.map(copy) :
(typeof o === 'object') ?
reduce(o, (p, c, k) =>
merge(p, { [k]: copy(c) }), {}) : o;
/**
* reduce an object's keys (in no guaranteed order)
*/
export const reduce = (o: Hash, f: ObjectReducer, accum?: B) =>
Object.keys(o).reduce((p, k) => f(p, o[k], k, o), accum);
/**
* map over an object (in no guaranteed oreder)
*/
export const map = (o: Hash, f: ObjectMapper) =>
Object.keys(o).map((k => f(o[k], k, o)));
/**
* compose two functions into one.
*/
export const compose = (f: (a: B) => C, g: (a: A) => B) => (x: A) => f(g(x));
/**
* fling removes a key from an object
* @param {string} key
* @param {object} object
* @return {Object}
* @summary {(string,Object) → Object}
*/
export const fling = (s: string, o: Hash) => {
if ((o == null) || (o.constructor !== Object))
throw new TypeError('fling(): only works with object literals!');
return Object.keys(o).reduce((o2, k) => k === s ? o2 : merge(o2, {
[k]: o[k]
}), {});
}
/**
* head returns the item at index 0 of an array
* @param {Array} list
* @return {*}
* @summary { Array → * }
*/
export const head = (list: A[]) => list[0];
/**
* tail returns the last item in an array
* @param {Array} list
* @return {*}
* @summary {Array → *}
*/
export const tail = (list: A[]) => list[list.length - 1];
/**
* constant given a value, return a function that always returns this value.
* @summary constant X → * → X
*
*/
export const constant = (a: A): ((_: any) => A) => () => a;
/**
* except copies an object removing a single key.
*/
export const except = , V>(keys: string[], o: O): O =>
reduce(o, (p, c, k) => keys.indexOf(k) > -1 ? p : merge(p, { [k]: c }), {});