/** * Composes single-argument functions from right to left. The rightmost * function can take multiple arguments as it provides the signature for * the resulting composite function. * * @param {...Function} funcs The functions to compose. * @returns {Function} A function obtained by composing the argument functions * from right to left. For example, compose(f, g, h) is identical to doing * (...args) => f(g(h(...args))). */ export function arrayUnique(array) { return Array.from((new Set(array)).values()); } export function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) } export function flatten(array) { return array.reduce((flattened, elm) => flattened.concat(elm), []); } export function virtualize(fields) { return (Superclass) => { class Virtualized extends Superclass {} fields.forEach((field) => { Virtualized.prototype[field] = function() { const prototype = Object.getPrototypeOf(this); const className = prototype.constructor.name; throw new ReferenceError( `"${className}" has undefined pure virtual method "${field}"` ); } }); return Virtualized; } } export function virtualizeStatic(fields) { return (Superclass) => { class Virtualized extends Superclass {} fields.forEach((field) => { Virtualized[field] = function() { const prototype = Virtualized.prototype; const className = prototype.constructor.name; throw new ReferenceError( `"${className}" has undefined pure virtual static method "${field}"` ); } }); return Virtualized; } } export class TickingPromise extends Promise { constructor(executor, ticker) { let _reject, _resolve; super((resolve, reject) => { _reject = reject; _resolve = resolve; if (executor) { executor(resolve, reject); } }); this.executor = executor; this.reject = _reject; this.resolve = _resolve; this.ticker = ticker; } static all(promises) { const tickingPromises = []; for (let i = 0; i < promises.length; i++) { const promise = promises[i]; if (promise instanceof TickingPromise) { tickingPromises.push(promise); // After resolution, stop ticking the promise. promise.then(() => { tickingPromises.splice(tickingPromises.indexOf(promise), 1); }) } } if (0 === tickingPromises.length) { return super.all(promises); } return new TickingPromise( (resolve) => { resolve(Promise.all(results)); }, (elapsed) => { for (let i = 0; i < tickingPromises.length; i++) { tickingPromises[i].tick(elapsed); } }, ); } tick(elapsed) { this.ticker(elapsed, this.resolve, this.reject); } } export {EventEmitterMixin as EventEmitter} from './event-emitter'; export {merge} from './merge'; export { mergeDiff, mergeDiffArray, mergeDiffObject, mergeDiffPrimitive, } from './merge-diff'; export {fastApply} from './fast-apply'; export {PropertyMixin as Property} from './property';