import { AsyncAutoTasks, Dictionary, auto as asyncAuto } from "async"; import highland from "highland"; const LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; export function generateRandomId(length: number): string { let randomPadId = ""; for(let i=0; i>> = { [P in keyof T]: Parameters }; */ type PromiseMap = { [P in keyof T]: PromiseLike | T[P] } export async function promiseProps(obj: PromiseMap): Promise { const result = { } as T; await Promise.all((Object.keys(obj) as Array).map(async (key) => { result[key] = (await obj[key]) as any; })); return result; } export function auto>(tasks: AsyncAutoTasks): Promise { // typing of async.auto is broken return asyncAuto(tasks) as any; } type PromiseCreatorMap = { [P in keyof T]: PromiseLike | ((...args: Array) => Promise) }; export function promiseAuto>(obj: PromiseCreatorMap): Promise { const promises = { } as PromiseMap; function _get(str: keyof T & string) { const dep = obj[str]; if(!dep) throw new Error("Invalid dependency '" + str + "' in promiseAuto()."); if(promises[str]) return promises[str]; if(dep instanceof Function) { const params = getFuncParams(dep) as Array; return promises[str] = _getDeps(params).then(function(res) { return (dep as any)(...params.map((param) => res[param])); }); } else { return Promise.resolve(dep as any); } } function _getDeps(arr: Array) { const deps = { } as PromiseMap; arr.forEach(function(it) { deps[it] = _get(it as string); }); return promiseProps(deps); } return _getDeps(Object.keys(obj) as Array); } function getFuncParams(func: Function) { // Taken from angular injector code const ARROW_ARG = /^([^(]+?)\s*=>/; const FN_ARGS = /^[^(]*\(\s*([^)]*)\)/m; const FN_ARG_SPLIT = /\s*,\s*/; const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; const fnText = (Function.prototype.toString.call(func) + ' ').replace(STRIP_COMMENTS, ''); const match = (fnText.match(ARROW_ARG) || fnText.match(FN_ARGS)); if (!match) { throw new Error("Could not parse function params."); } const params = match[1]; return params == "" ? [ ] : params.split(FN_ARG_SPLIT); } export function clone(obj: T): T { return obj == null ? obj : JSON.parse(JSON.stringify(obj)); } export function throttle(func: (...args: A) => Promise, parallel = 1): (...args: A) => Promise { const stream = highland<() => Promise>(); stream.map((func) => (highland(func()))).parallel(parallel).done(() => undefined); return (...args: A): Promise => { return new Promise((resolve, reject) => { stream.write(() => { return func(...args).then(resolve).catch(reject); }); }); }; }