safe
Version:
Starting from version 0.4.0 safejs implements almost all functions of [Async](https://github.com/caolan/async) and can transparently replace it. For asyncjs functions library adds its error trap capabilities and also contain some optimizations and speed i
2,705 lines (2,364 loc) • 53.2 kB
JavaScript
/*!
* safejs
* https://github.com/sergeyksv/safejs
*
* Copyright 2012-2023 PushOk Software
* Licensed under MIT
*/
!(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.safe = {})));
}(this, (function (exports) {
"use strict";
const UNDEFINED = 'undefined',
OBJECT = 'object',
FUNCTION = 'function',
_keys = Object.keys,
_isArray = Array.isArray,
_MAX = Infinity,
_hop = Object.prototype.hasOwnProperty,
_alreadyError = "Callback was already called.",
_typedErrors = [
"Array or Object are required",
"Array is required",
"Exactly two arguments are required",
"Function is required"
];
/* +++++++++++++++++++++++++ private functions +++++++++++++++++++++++++ */
/**
* @name noop
* @static
* @method
*/
const noop = () => {};
const _isObject = (obj) => {
if (obj === null)
return false;
const type = typeof obj;
return type === OBJECT || type === FUNCTION;
};
const _isUndefined = (val) => {
return typeof val === UNDEFINED;
};
const _isFunction = (fn) => {
return typeof fn === FUNCTION;
};
const _isPromiseLike = (p) => {
return p && _isFunction(p.then);
};
const _byData = (item) => {
if (item)
return item['data'];
};
const _isAsyncFunction = (f) => {
return f && f.constructor && f.constructor.name === 'AsyncFunction';
};
const _throwError = (text, callback) => {
const err = new TypeError(text);
if (!_isFunction(callback) || callback === noop) {
throw err;
}
callback(err);
};
const _once = (callback) => {
let fired = false;
return (...args) => {
if (fired || callback == null)
return;
fired = true;
return callback(...args);
};
};
const _only_once = (callback) => {
let fired = false;
return (...args) => {
if (fired) {
throw new Error(_alreadyError);
}
fired = true;
return callback(...args);
};
};
const _iterator_array = (arr) => {
let i = -1;
return {
next: () => {
i++;
return i < arr.length ? {
value: arr[i],
key: i,
done: false
} : {
done: true
};
}
};
};
const _iterator_symbol = (obj) => {
let i = -1;
const iterator = obj[Symbol.iterator]();
return {
next: () => {
i++;
const item = iterator.next();
return item.done ? {
done: true
} : {
value: item.value,
key: i,
done: false
};
}
};
};
const _iterator_obj = (obj) => {
const keys = _keys(obj),
l = keys.length;
let i = -1;
return {
next: () => {
i++;
const k = keys[i];
return i < l ? {
value: obj[k],
key: k,
done: false
} : {
done: true
};
}
};
};
const _iterator = (obj) => {
if (_isArray(obj)) {
return _iterator_array(obj);
}
if (obj[typeof Symbol === FUNCTION && Symbol.iterator]) {
return _iterator_symbol(obj);
}
return _iterator_obj(obj);
};
const _eachLimit = (obj, limit, fn, callback) => {
let running = 0,
stop = false,
iterator = _iterator(obj),
err = false;
const _callback = _once(callback);
function task () {
if (stop || err)
return;
while (running < limit && err === false) {
let item = iterator.next();
if (item.done) {
stop = true;
if (running <= 0) {
_callback();
}
break;
}
running++;
fn(item.value, item.key, (_err) => {
running--;
if (_err) {
err = true;
_callback(_err);
} else if (stop === false && running < limit) {
task();
} else if (stop && running <= 0) {
_callback();
}
});
}
}
task();
};
const _doPsevdoAsync = (fn) => {
return (cb) => cb(null, fn());
};
const _back = (() => {
if (typeof setImmediate === FUNCTION) {
return setImmediate;
}
if (typeof queueMicrotask === FUNCTION) {
return (callback, ...args) => {
queueMicrotask(() => {
callback(...args);
});
};
}
if (typeof process === UNDEFINED) {
if (typeof Image === FUNCTION) { // browser polyfill
return (callback, ...args) => {
// eslint-disable-next-line no-undef
const img = new Image;
img.onerror = () => {
callback(...args);
};
img.src = 'data:image/png,0';
};
}
return (callback, ...args) => {
setTimeout(callback, 0, ...args);
};
}
return (callback, ...args) => {
process.nextTick(() => {
callback(...args);
});
};
})();
/* +++++++++++++++++++++++++ public functions +++++++++++++++++++++++++ */
/**
* @name back
* @static
* @method
* @alias setImmediate
* @alias yield
* @param {Function} callback
* @param {...any} [args]
*/
const back = (...args) => {
if (!_isFunction(args[0]))
throw new TypeError(_typedErrors[3]);
_back(...args);
};
const _resolvePromise = (pr, callback) => {
pr.then((result) => {
back(callback, null, result);
}, (err) => {
back(callback, err);
});
};
/**
* @name run
* @static
* @method
* @param {Function} fn
* @param {Function} callback
*/
const run = (fn, callback) => {
if (_isAsyncFunction(fn)) {
_resolvePromise(fn(), callback);
return;
}
let getPromise, res, fired = false;
try {
res = fn(fin);
} catch (err) {
if (!err)
throw err;
_back(fin, err);
}
if (_isPromiseLike(res)) {
getPromise = "Resolution method is overspecified. Call a callback *or* return a Promise.";
if (fired) {
throw new Error(getPromise);
}
_resolvePromise(res, fin);
}
function fin (...args) {
if (fired) {
throw args[0] || new Error(getPromise || _alreadyError);
}
fired = true;
callback(...args);
}
};
const _map = (obj, limit, fn, callback) => {
if (!_isObject(obj)) {
return _throwError(_typedErrors[0], callback);
}
const result = [];
let idx = 0;
_eachLimit(obj, limit, (item, key, cb) => {
const i = idx++;
run((_cb) => fn(item, _cb), (err, res) => {
result[i] = res;
cb(err);
});
}, (err) => {
callback(err, result);
});
};
const _mapValues = (obj, limit, fn, callback) => {
if (!_isObject(obj)) {
return _throwError(_typedErrors[0], callback);
}
const result = {};
_eachLimit(obj, limit, (item, key, cb) => {
run((_cb) => fn(item, key, _cb), (err, res) => {
result[key] = res;
cb(err);
});
}, (err) => {
callback(err, result);
});
};
const _groupBy = (obj, limit, fn, callback) => {
if (!_isObject(obj)) {
return _throwError(_typedErrors[0], callback);
}
_map(obj, limit, (item, cb) => {
run((_cb) => fn(item, _cb), (err, key) => {
if (err)
return cb(err);
cb(err, {
key,
val: item
});
});
}, (err, mapResults) => {
const result = {};
mapResults.forEach((data) => {
if (_hop.call(result, data.key))
result[data.key].push(data.val);
else
result[data.key] = [data.val];
});
callback(err, result);
});
};
const _filter = (trust, arr, limit, fn, callback) => {
if (!_isArray(arr)) {
return _throwError(_typedErrors[1], callback);
}
const result = [];
_eachLimit(arr, limit, (item, key, cb) => {
run((_cb) => fn(item, _cb), (err, is) => {
if ((trust && is) || !(trust || is)) {
result.push({
data: item,
i: key
});
}
cb(err);
});
}, (err) => {
callback(err, result.sort((a, b) => a.i - b.i).map(_byData));
});
};
const _test = (trust, arr, limit, fn, callback) => {
let result = trust;
_eachLimit(arr, limit, (item, key, cb) => {
run((_cb) => fn(item, _cb), (is) => {
if (trust) {
if (!is) {
result = false;
}
cb(!is);
} else {
if (is) {
result = true;
}
cb(result);
}
});
}, () => callback(result));
};
const _controlFlow = (obj, limit, callback) => {
const result = _isArray(obj) ? [] : {};
_eachLimit(obj, limit, (item, key, cb) => {
run(item, (err, ...args) => {
if (args.length) {
result[key] = args.length === 1 ? args[0] : args;
} else {
result[key] = null;
}
cb(err);
});
}, (err) => {
callback(err, result);
});
};
const _times = (times, limit, fn, callback) => {
const t = parseInt(times),
arr = Array(t);
for (let i = 0; i < t; i++) {
arr[i] = i;
}
_map(arr, limit, fn, callback);
};
const _detect = (arr, limit, fn, callback) => {
let result;
_eachLimit(arr, limit, (item, key, cb) => {
run((_cb) => fn(item, _cb), (is) => {
if (is)
result = item;
cb(result || null);
});
}, () => callback(result));
};
const _concat = (arr, limit, fn, callback) => {
if (!_isArray(arr)) {
return _throwError(_typedErrors[1], callback);
}
_map(arr, limit, fn, (err, result) => {
callback(err, [].concat(...result));
});
};
/**
* @name result
* @static
* @method
* @param {Function} callback
* @param {Function} fn
* @return {Function} wrapped function
*/
const result = (callback, fn) => {
if (!_isFunction(fn) || !_isFunction(callback))
throw new TypeError(_typedErrors[2]);
return function _wrappedFn(...args) {
let res;
try {
res = fn.apply(this, args);
} catch (err) {
if (!err)
throw err;
callback(err);
return;
}
if (!_isUndefined(res))
back(callback, null, res);
else
back(callback, null);
};
};
/**
* @name sure_result
* @static
* @method
* @alias trap_sure_result
* @param {Function} callback
* @param {Function} fn
* @return {Function} wrapped function
*/
const sure_result = (callback, fn) => {
if (!_isFunction(fn) || !_isFunction(callback))
throw new TypeError(_typedErrors[2]);
/**
* @param {Error} [err=null]
* @param {...any} args
*/
return function _wrappedFn(err, ...args) {
if (err) {
callback(err);
return;
}
let res;
try {
res = fn.apply(this, args);
} catch (_err) {
if (!_err)
throw _err;
back(callback, _err);
return;
}
if (!_isUndefined(res))
back(callback, null, res);
else
back(callback, null);
};
};
/**
* @name sure
* @static
* @method
* @alias trap_sure
* @param {Function} callback
* @param {Function|any} fn
* @return {Function} wrapped function
*/
const sure = (callback, fn) => {
if (_isUndefined(fn) || !_isFunction(callback))
throw new TypeError(_typedErrors[2]);
/**
* @param {Error} [err=null]
* @param {...any} args
* @return {any}
*/
return function _wrappedFn(err, ...args) {
if (err) {
callback(err);
} else if (!_isFunction(fn)) {
back(callback, null, fn);
} else {
try {
return fn.apply(this, args);
} catch (_err) {
if (!_err)
throw _err;
back(callback, _err);
}
}
};
};
/**
* @name trap
* @static
* @method
* @param {Function} callback
* @param {Function} [fn]
* @return {Function} wrapped function
*/
const trap = (callback, fn) => {
if (_isUndefined(callback))
throw new TypeError(_typedErrors[2]);
/**
* @param {Error} [err=null]
* @param {...any} args
* @return {any}
*/
return function _wrappedFn(...args) {
/*eslint-disable no-param-reassign*/
if (_isUndefined(fn)) {
fn = callback;
callback = args[args.length - 1];
}
/*eslint-enable no-param-reassign*/
try {
return fn.apply(this, args);
} catch (err) {
if (!err)
throw err;
back(callback, err);
}
};
};
/**
* @name wrap
* @static
* @method
* @param {Function} fn
* @param {Function} callback
* @return {Function} wrapped function
*/
const wrap = (fn, callback) => {
if (!_isFunction(fn) || !_isFunction(callback))
throw new TypeError(_typedErrors[2]);
/**
* @param {...any} args
* @return {any}
*/
return function _wrappedFn(...args) {
args.push(callback);
try {
return fn.apply(this, args);
} catch (err) {
if (!err)
throw err;
back(callback, err);
}
};
};
/**
* @name sure_spread
* @static
* @method
* @param {Function} callback
* @param {Function} fn
* @return {Function} wrapped function
*/
const sure_spread = (callback, fn) => {
if (_isUndefined(fn) || !_isFunction(callback))
throw new TypeError(_typedErrors[2]);
/**
* @param {Error} [err=null]
* @param {...any} args
* @return {any}
*/
return function _wrappedFn(err, ...args) {
if (err) {
callback(err);
return;
}
try {
return fn.apply(this, args[0]);
} catch (_err) {
if (!_err)
throw _err;
back(callback, _err);
}
};
};
/**
* @name spread
* @static
* @method
* @param {Function} fn
* @return {Function} wrapped function
*/
const spread = (fn) => {
/**
* @param {Array} args
* @return {any}
*/
return function _wrappedFn(args) {
return fn.apply(this, args);
};
};
const _swhile = (test, fn, dir, before, callback) => {
if (before) {
tester();
} else {
task();
}
function task () {
run(fn, sure(callback, tester));
}
function tester (result) {
run(test, sure(callback, (res) => {
if (res == dir) {
callback(null, result);
} else {
task();
}
}));
}
};
const _reduce = (arr, memo, fn, callback = noop, direction) => {
if (!_isArray(arr)) {
return _throwError(_typedErrors[1], callback);
}
const iterator = _iterator(arr),
len = arr.length;
const task = (err, _memo) => {
if (err) {
callback(err);
return;
}
const item = iterator.next();
if (item.done) {
callback(null, _memo);
} else {
run((cb) => fn(_memo, direction ? item.value : arr[len - 1 - item.key], cb), task);
}
};
task(null, memo);
};
const _applyEach = (limit) => {
/**
* @name applyEach
* @static
* @method
* @param {Object|Array|Iterable} fns
* @param {...any} [args]
* @param {Function} callback
* @return {any}
*/
return function applyEach(fns, ...args) {
const task = function task(...args2) {
const callback = args2.pop();
_eachLimit(fns, limit, (fn, key, cb) => {
run((_cb) => {
return fn.apply(this, args2.concat(_cb));
}, cb);
}, callback);
};
if (args.length === 0) {
return task;
}
return task.apply(this, args);
};
};
/**
* @class
*/
class _Queue {
/**
* Create a queue.
* @param {Function} worker
* @param {number} concurrency
*/
constructor(worker, concurrency) {
const _concurrency = parseInt(concurrency);
if (!_concurrency) {
throw new TypeError('Concurrency must not be zero');
}
Object.defineProperties(this, {
'__worker': {
enumerable: false,
configurable: false,
writable: false,
value: worker
},
'__workers': {
enumerable: false,
configurable: false,
writable: true,
value: 0
},
'__workersList': {
enumerable: false,
configurable: false,
writable: true,
value: []
},
'__isProcessing': {
enumerable: false,
configurable: false,
writable: true,
value: false
},
'__processingScheduled': {
enumerable: false,
configurable: false,
writable: true,
value: false
},
'tasks': {
enumerable: false,
configurable: false,
writable: false,
value: []
},
'concurrency': {
enumerable: true,
configurable: false,
writable: true,
value: _concurrency
},
'buffer': {
enumerable: true,
configurable: false,
writable: true,
value: _concurrency / 4
},
'started': {
enumerable: true,
configurable: false,
writable: true,
value: false
},
'paused': {
enumerable: true,
configurable: false,
writable: true,
value: false
}
});
}
__insert(data, pos, callback) {
if (callback != null && !_isFunction(callback)) {
throw new TypeError(_typedErrors[3]);
}
this.started = true;
const _data = _isArray(data) ? data : [data];
if (_data.length === 0 && this.idle()) {
return _back(() => {
this.drain();
});
}
const arr = _data.map((task) => {
return {
data: task,
callback: _only_once(callback || noop)
};
});
if (pos) {
this.tasks.unshift(...arr);
} else {
this.tasks.push(...arr);
}
if (!this.__processingScheduled) {
this.__processingScheduled = true;
_back(() => {
this.__processingScheduled = false;
this.__execute();
});
}
}
__execute() {
if (this.__isProcessing)
return;
this.__isProcessing = true;
while (!this.paused && this.__workers < this.concurrency && this.tasks.length) {
let task = this.tasks.shift();
this.__workersList.push(task);
if (this.tasks.length === 0)
this.empty();
let data = task.data;
this.__workers++;
if (this.__workers === this.concurrency)
this.saturated();
run((cb) => {
return this.__worker(data, cb);
}, (...args) => {
this.__workers--;
const index = this.__workersList.indexOf(task);
if (index === 0) {
this.__workersList.shift();
} else if (index > 0) {
this.__workersList.splice(index, 1);
}
task.callback(...args);
if (args[0]) {
this.error(args[0], data);
}
if (this.__workers <= this.concurrency - this.buffer) {
this.unsaturated();
}
if (this.idle())
this.drain();
this.__execute();
});
}
this.__isProcessing = false;
}
/**
* remove items from the queue that match a test function
* @param {Function} test function
*/
remove(test) {
let tasks = this.tasks.filter((item) => !test(item.data));
this.tasks.length = tasks.length;
tasks.forEach((item, key) => {
this.tasks[key] = item;
});
}
/**
* add a new task to the queue
* @param {any} data
* @param {Function} callback
*/
push(data, callback) {
this.__insert(data, false, callback);
}
/**
* callback that is called when the number of running workers
* hits the `concurrency` limit, and further tasks will be queued.
*/
saturated() {}
/**
* a callback that is called when the number of running workers
* is less than the `concurrency` & `buffer` limits, and
* further tasks will not be queued.
*/
unsaturated() {}
/**
* a callback that is called when the last item
* from the `queue` is given to a `worker`.
*/
empty() {}
/**
* a callback that is called when the last item
* from the `queue` has returned from the `worker`.
*/
drain() {}
/**
* a callback that is called when a task errors.
* @param {Error} err
* @param {any} task
*/
error() {}
/**
* a function that removes the `drain` callback
* and empties remaining tasks from the queue
*/
kill() {
delete this.drain;
this.tasks.length = 0;
}
/**
* a function returning the number of items in the queue
* @return {number} length
*/
length() {
return this.tasks.length;
}
/**
* a function returning the array of items of the queue
* @return {Array} workers
*/
running() {
return this.__workers;
}
/**
* a function returning false if there are items
* waiting or being processed, or true if not
* @return {boolena} processed
*/
idle() {
return this.tasks.length + this.__workers === 0;
}
/**
* a function that pauses the processing of tasks
*/
pause() {
this.paused = true;
}
/**
* a function that resumes the processing of the queued tasks
*/
resume() {
if (!this.paused)
return;
this.paused = false;
_back(() => this.__execute());
}
/**
* a function returning the array of items currently being processed
* @return {Array} an active workers
*/
workersList() {
return this.__workersList;
}
}
/**
* Creates a new priority queue.
* @name PriorityQueue
* @class
* @extends _Queue
*/
class PriorityQueue extends _Queue {
/**
* Create a queue.
* @param {Function} worker
* @param {number} concurrency
*/
constructor(worker, concurrency) {
super(worker, concurrency, 'Priority Queue');
}
/**
* add a new task to the queue
* @param {any} data
* @param {number} priority
* @param {Function} callback
*/
push(data, priority, callback) {
this.__insert(data, priority || 0, callback);
}
__insert(data, prior, callback) {
if (callback != null && !_isFunction(callback)) {
throw new TypeError(_typedErrors[3]);
}
this.started = true;
const _data = _isArray(data) ? data : [data];
if (_data.length === 0 && this.idle()) {
return _back(() => {
this.drain();
});
}
const arr = _data.map((task) => {
return {
data: task,
priority: prior,
callback: _only_once(callback || noop)
};
});
let tlen = this.tasks.length,
firstidx = tlen ? this.tasks[0].priority : 0,
lastidx = tlen ? this.tasks[tlen - 1].priority : 0;
if (prior > firstidx) {
this.tasks.unshift(...arr);
} else {
this.tasks.push(...arr);
}
if (firstidx >= prior && prior < lastidx) {
this.tasks.sort((b, a) => a.priority - b.priority); // reverse sort
}
if (!this.__processingScheduled) {
this.__processingScheduled = true;
_back(() => {
this.__processingScheduled = false;
this.__execute();
});
}
}
}
/**
* Creates a new queue.
* @name Queue
* @class
* @extends _Queue
*/
class Queue extends _Queue {
/**
* Create a queue.
* @param {Function} worker
* @param {number} concurrency
*/
constructor(worker, concurrency) {
super(worker, concurrency, 'Queue');
}
/**
* add a new task to the front of the queue
* @param {any} data
* @param {Function} callback
*/
unshift(data, callback) {
this.__insert(data, true, callback);
}
}
/**
* Creates a new cargo queue.
* @name CargoQueue
* @class
* @extends _Queue
*/
class CargoQueue extends _Queue {
/**
* Create a cargo queue.
* @param {Function} worker
* @param {number} payload
*/
constructor(worker, payload) {
super(worker, 1, 'Cargo');
const _payload = parseInt(payload);
if (!_payload) {
throw new TypeError('Payload must not be zero');
}
Object.defineProperties(this, {
'payload': {
enumerable: true,
configurable: false,
writable: true,
value: _payload
}
});
}
__execute() {
if (this.__isProcessing)
return;
this.__isProcessing = true;
while (!this.paused && this.__workers < this.concurrency && this.tasks.length) {
let tasks = this.tasks.splice(0, this.payload);
this.__workersList.push(...tasks);
if (this.tasks.length === 0)
this.empty();
let data = tasks.map(_byData);
this.__workers++;
if (this.__workers === this.concurrency)
this.saturated();
run((cb) => {
return this.__worker(data, cb);
}, (...args) => {
this.__workers--;
tasks.forEach((task) => {
const index = this.__workersList.indexOf(task);
if (index === 0) {
this.__workersList.shift();
} else if (index > 0) {
this.__workersList.splice(index, 1);
}
task.callback(...args);
});
if (this.__workers <= this.concurrency - this.buffer) {
this.unsaturated();
}
if (this.idle())
this.drain();
this.__execute();
});
}
this.__isProcessing = false;
}
}
/**
* @name nextTick
* @static
* @method
* @param {Function} callback
*/
const nextTick = (typeof process !== UNDEFINED && process.nextTick) ? process.nextTick : typeof queueMicrotask === FUNCTION ? queueMicrotask : _back;
/**
* @name apply
* @static
* @method
* @param {Function} fn
* @param {...ary} args
* @return {Function} wrapped function
*/
const apply = (fn, ...args) => {
/**
* @param {...any} args2
* @return {any}
*/
const _wrappedFn = (...args2) => fn(...args, ...args2);
return _wrappedFn;
};
/**
* @deprecated
* @name args
* @static
* @method
* @param {...any} args
* @return {Array}
*/
const argToArr = function argToArr(...args) {
const len = args.length,
rest = parseInt(this);
if (rest !== rest) // check for NaN
throw new Error('Pass arguments to "safe.args" only through ".apply" method!');
if (len === 0 || rest > len)
return [];
const arr = Array(len - rest);
for (let i = rest; i < len; i++) {
arr[i - rest] = i < 0 ? null : args[i];
}
return arr;
};
/**
* @name constant
* @static
* @method
* @param {...Array} args
* @return {Function}
*/
const constant = (...args) => {
/**
* @param {Function} callback
* @return {any}
*/
return (callback) => {
return callback(null, ...args);
};
};
/**
* @name ensureAsync
* @static
* @method
* @param {Function} fn
* @return {Function} wrapped function
*/
const ensureAsync = (fn) => {
/**
* {...any} args
* @param {Function} callback
* @return {any}
*/
return function _wrappedFn(...args) {
let sync = true;
const callback = args[args.length - 1];
args[args.length - 1] = function _wrappedCallback(...args2) {
if (sync)
_back(() => callback.apply(this, args2));
else
callback.apply(this, args2);
};
const r = fn.apply(this, args);
sync = false;
return r;
};
};
/**
* @name asyncify
* @static
* @method
* @alias wrapSync
* @param {AyncFunction} fn
* @return {Function} wrapped function
*/
const asyncify = (fn) => {
/**
* {...any} args
* @param {Function} callback
*/
return function _wrappedFn(...args) {
const callback = args.pop();
run((cb) => {
const res = fn.apply(this, args);
return (_isAsyncFunction(fn) || _isPromiseLike(res)) ? res : cb(null, res);
}, callback);
};
};
/**
* @name inherits
* @static
* @method
* @param {Function} ctor - class
* @param {Function} superCtor - super class
*/
const inherits = (ctor, superCtor) => {
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false
}
});
};
/**
* @name async
* @static
* @method
* @param {Object} _this - context object
* @param {Function} fn
* @param {...any} args
* @return {Function} wrapped function
*/
const async = (_this, fn, ...args) => {
/**
* @param {Function} callback
* @return {any}
*/
const _wrappedFn = (callback) => {
try {
return _this[fn](...args.concat(callback));
} catch (err) {
if (!err)
throw err;
back(callback, err);
}
};
return _wrappedFn;
};
/**
* @name sortBy
* @static
* @method
* @param {Array} arr
* @param {Function} fn
* @param {Function} [callback]
*/
const sortBy = (arr, fn, callback = noop) => {
if (!_isArray(arr)) {
_throwError(_typedErrors[1], callback);
return;
}
const _result = [];
_eachLimit(arr, _MAX, (item, key, cb) => {
run((_cb) => fn(item, _cb), (err, res) => {
_result[key] = {
data: item,
i: res
};
cb(err);
});
}, (err) => {
callback(err, _result.sort((a, b) => a.i - b.i).map(_byData));
});
};
/**
* @name waterfall
* @static
* @method
* @param {Function[]} tasks
* @param {Function} [callback]
*/
const waterfall = (tasks, callback = noop) => {
if (!_isArray(tasks)) {
_throwError(_typedErrors[1], callback);
return;
}
const iterator = _iterator(tasks);
const task = (err, ...args) => {
if (err) {
callback(err);
return;
}
const item = iterator.next();
if (item.done) {
callback(null, ...args);
} else {
run((cb) => {
return item.value(...args, cb);
}, task);
}
};
task();
};
/**
* @name series
* @static
* @method
* @param {Function[]|Object<string,Function>} tasks
* @param {Function} [callback]
*/
const series = (tasks, callback = noop) => {
_controlFlow(tasks, 1, callback);
};
/**
* @name parallel
* @static
* @method
* @param {Function[]|Object<string,Function>} tasks
* @param {Function} [callback]
*/
const parallel = (tasks, callback = noop) => {
_controlFlow(tasks, _MAX, callback);
};
/**
* @name parallelLimit
* @static
* @method
* @param {Function[]|Object<string,Function>} tasks
* @param {number} limit
* @param {Function} [callback]
*/
const parallelLimit = (tasks, limit, callback = noop) => {
_controlFlow(tasks, limit, callback);
};
/**
* @name reduce
* @static
* @method
* @alias inject
* @alias foldl
* @param {Array} arr
* @param {any} memo
* @param {Function} iterator
* @param {Function} [callback]
*/
const reduce = (arr, memo, iterator, callback = noop) => {
_reduce(arr, memo, iterator, callback, 1);
};
/**
* @name reduceRight
* @static
* @method
* @alias foldr
* @param {Array} arr
* @param {any} memo
* @param {Function} iterator
* @param {Function} [callback]
*/
const reduceRight = (arr, memo, iterator, callback = noop) => {
_reduce(arr, memo, iterator, callback, 0);
};
/**
* @name each
* @static
* @method
* @alias forEach
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const forEach = (arr, iterator, callback = noop) => {
if (!_isArray(arr)) {
_throwError(_typedErrors[1], callback);
return;
}
_eachLimit(arr, _MAX, (item, key, cb) => {
run((_cb) => iterator(item, _cb), cb);
}, callback);
};
/**
* @name eachLimit
* @static
* @method
* @alias forEachLimit
* @param {Array} arr
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const eachLimit = (arr, limit, iterator, callback = noop) => {
if (!_isArray(arr)) {
_throwError(_typedErrors[1], callback);
return;
}
_eachLimit(arr, limit, (item, key, cb) => {
run((_cb) => iterator(item, _cb), cb);
}, callback);
};
/**
* @name eachSeries
* @static
* @method
* @alias forEachSeries
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const eachSeries = (arr, iterator, callback = noop) => {
if (!_isArray(arr)) {
_throwError(_typedErrors[1], callback);
return;
}
_eachLimit(arr, 1, (item, key, cb) => {
run((_cb) => iterator(item, _cb), cb);
}, callback);
};
/**
* @name eachOf
* @static
* @method
* @alias forEachOf
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
*/
const eachOf = (obj, iterator, callback = noop) => {
if (!_isObject(obj)) {
_throwError(_typedErrors[0], callback);
return;
}
_eachLimit(obj, _MAX, (item, key, cb) => {
run((_cb) => iterator(item, key, _cb), cb);
}, callback);
};
/**
* @name eachOfLimit
* @static
* @method
* @alias forEachOfLimit
* @param {Object|Array|Iterable} obj
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const eachOfLimit = (obj, limit, iterator, callback = noop) => {
if (!_isObject(obj)) {
_throwError(_typedErrors[0], callback);
return;
}
_eachLimit(obj, limit, (item, key, cb) => {
run((_cb) => iterator(item, key, _cb), cb);
}, callback);
};
/**
* @name eachOfSeries
* @static
* @method
* @alias forEachOfSeries
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
*/
const eachOfSeries = (obj, iterator, callback = noop) => {
if (!_isObject(obj)) {
_throwError(_typedErrors[0], callback);
return;
}
_eachLimit(obj, 1, (item, key, cb) => {
run((_cb) => iterator(item, key, _cb), cb);
}, callback);
};
/**
* @name map
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
*/
const map = (obj, iterator, callback = noop) => {
_map(obj, _MAX, iterator, callback);
};
/**
* @name mapLimit
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const mapLimit = (obj, limit, iterator, callback = noop) => {
_map(obj, limit, iterator, callback);
};
/**
* @name mapSeries
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
*/
const mapSeries = (obj, iterator, callback = noop) => {
_map(obj, 1, iterator, callback);
};
/**
* @name mapValues
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
*/
const mapValues = (obj, iterator, callback = noop) => {
_mapValues(obj, _MAX, iterator, callback);
};
/**
* @name mapValuesLimit
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const mapValuesLimit = (obj, limit, iterator, callback = noop) => {
_mapValues(obj, limit, iterator, callback);
};
/**
* @name mapValuesSeries
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
*/
const mapValuesSeries = (obj, iterator, callback = noop) => {
_mapValues(obj, 1, iterator, callback);
};
/**
* @name concat
* @static
* @method
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const concat = (arr, iterator, callback = noop) => {
_concat(arr, _MAX, iterator, callback);
};
/**
* @name concatLimit
* @static
* @method
* @param {Array} arr
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const concatLimit = (arr, limit, iterator, callback = noop) => {
_concat(arr, limit, iterator, callback);
};
/**
* @name concatSeries
* @static
* @method
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const concatSeries = (arr, iterator, callback = noop) => {
_concat(arr, 1, iterator, callback);
};
/**
* @name groupBy
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
*/
const groupBy = (obj, iterator, callback = noop) => {
_groupBy(obj, _MAX, iterator, callback);
};
/**
* @name groupByLimit
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const groupByLimit = (obj, limit, iterator, callback = noop) => {
_groupBy(obj, limit, iterator, callback);
};
/**
* @name groupBySeries
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
*/
const groupBySeries = (obj, iterator, callback = noop) => {
_groupBy(obj, 1, iterator, callback);
};
/**
* @name filter
* @static
* @method
* @alias select
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const filter = (arr, iterator, callback = noop) => {
_filter(true, arr, _MAX, iterator, callback);
};
/**
* @name filterLimit
* @static
* @method
* @alias selectLimit
* @param {Array} arr
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const filterLimit = (arr, limit, iterator, callback = noop) => {
_filter(true, arr, limit, iterator, callback);
};
/**
* @name filterSeries
* @static
* @method
* @alias selectSeries
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const filterSeries = (arr, iterator, callback = noop) => {
_filter(true, arr, 1, iterator, callback);
};
/**
* @name reject
* @static
* @method
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const reject = (arr, iterator, callback = noop) => {
_filter(false, arr, _MAX, iterator, callback);
};
/**
* @name rejectLimit
* @static
* @method
* @param {Array} arr
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const rejectLimit = (arr, limit, iterator, callback = noop) => {
_filter(false, arr, limit, iterator, callback);
};
/**
* @name rejectSeries
* @static
* @method
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const rejectSeries = (arr, iterator, callback = noop) => {
_filter(false, arr, 1, iterator, callback);
};
/**
* @name some
* @static
* @method
* @alias any
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const some = (arr, iterator, callback = noop) => {
_test(false, arr, _MAX, iterator, callback);
};
/**
* @name someLimit
* @static
* @method
* @alias anyLimit
* @param {Array} arr
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const someLimit = (arr, limit, iterator, callback = noop) => {
_test(false, arr, limit, iterator, callback);
};
/**
* @name someSeries
* @static
* @method
* @alias anySeries
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const someSeries = (arr, iterator, callback = noop) => {
_test(false, arr, 1, iterator, callback);
};
/**
* @name every
* @static
* @method
* @alias all
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const every = (arr, iterator, callback = noop) => {
_test(true, arr, _MAX, iterator, callback);
};
/**
* @name everyLimit
* @static
* @method
* @alias allLimit
* @param {Array} arr
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const everyLimit = (arr, limit, iterator, callback = noop) => {
_test(true, arr, limit, iterator, callback);
};
/**
* @name everySeries
* @static
* @method
* @alias allSeries
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const everySeries = (arr, iterator, callback = noop) => {
_test(true, arr, 1, iterator, callback);
};
/**
* @name auto
* @static
* @method
* @param {Object.<string,Function|string[]>} tasks
* @param {number} [limit=Infinity]
* @param {Function} [callback]
*/
const auto = (tasks, limit, callback) => {
const res = {},
starter = Object.create(null),
_tasks = _keys(tasks);
let stop,
qnt = _tasks.length,
running = 0,
unresolve = null;
/*eslint-disable no-param-reassign*/
if (_isFunction(limit)) {
callback = limit;
limit = _MAX;
}
/*eslint-enable no-param-reassign*/
// check dependencies
_tasks.forEach((key) => {
if (unresolve)
return;
const target = tasks[key];
if (_isArray(target)) {
let dependencies = target.slice(0, target.length - 1);
for (let i = 0; i < dependencies.length; i++) {
let dep = _hop.call(tasks, target[i]) ? tasks[target[i]] : null;
if (!dep) {
unresolve = new Error(`safe.auto task \`${key}\` has a non-existent dependency \`${target[i]}\` in ${dependencies.join(', ')}`);
break;
}
if ((dep === key) || (_isArray(dep) && dep.indexOf(key) !== -1)) {
unresolve = new Error(`safe.auto cannot execute tasks due to a recursive dependency`);
break;
}
}
}
});
if (unresolve) {
if (_isFunction(callback)) {
callback(unresolve);
return;
}
throw new Error(unresolve);
}
const _callback = _once(callback);
function task () {
_tasks.forEach((k) => {
if (stop || running >= limit || starter[k]) {
return;
}
let fn;
const target = tasks[k];
if (_isArray(target)) {
let fin = target.length - 1;
for (let i = 0; i < fin; i++) {
if (!_hop.call(res, target[i])) {
return;
}
}
fn = target[fin];
} else {
fn = target;
}
starter[k] = true;
running++;
run((cb) => fn(cb, res), (err, ...args) => {
qnt--;
running--;
if (stop) {
return;
}
stop = err || qnt === 0;
if (err) {
_callback(err, res);
} else {
if (args.length) {
res[k] = args.length === 1 ? args[0] : args;
} else {
res[k] = null;
}
if (stop) {
_callback(err, res);
} else {
task();
}
}
});
});
}
task();
};
/**
* @name whilst
* @static
* @method
* @param {Function} test
* @param {Function} iterator
* @param {Function} [callback]
*/
const whilst = (test, iterator, callback = noop) => {
_swhile(_doPsevdoAsync(test), iterator, false, true, callback);
};
/**
* @name doWhilst
* @static
* @method
* @param {Function} iterator
* @param {Function} test
* @param {Function} [callback]
*/
const doWhilst = (iterator, test, callback = noop) => {
_swhile(_doPsevdoAsync(test), iterator, false, false, callback);
};
/**
* @name during
* @static
* @method
* @param {Function} test
* @param {Function} iterator
* @param {Function} [callback]
*/
const during = (test, iterator, callback = noop) => {
_swhile(test, iterator, false, true, callback);
};
/**
* @name doDuring
* @static
* @method
* @param {Function} iterator
* @param {Function} test
* @param {Function} [callback]
*/
const doDuring = (iterator, test, callback = noop) => {
_swhile(test, iterator, false, false, callback);
};
/**
* @name until
* @static
* @method
* @param {Function} test
* @param {Function} iterator
* @param {Function} [callback]
*/
const until = (test, iterator, callback = noop) => {
_swhile(_doPsevdoAsync(test), iterator, true, true, callback);
};
/**
* @name doUntil
* @static
* @method
* @param {Function} iterator
* @param {Function} test
* @param {Function} [callback]
*/
const doUntil = (iterator, test, callback = noop) => {
_swhile(_doPsevdoAsync(test), iterator, true, false, callback);
};
/**
* @name forever
* @static
* @method
* @param {Function} iterator
* @param {Function} callback
*/
const forever = (iterator, callback = noop) => {
const _callback = _only_once(callback),
_fn = ensureAsync(iterator);
function task () {
_fn(sure(_callback, task));
}
task();
};
/**
* @name memoize
* @static
* @method
* @param {Function} fn
* @param {Function} hasher
* @return {Function}
*/
const memoize = (fn, hasher = ((v) => v)) => {
const memo = {};
const queues = {};
const memoized = (...args) => {
const callback = args.pop(),
key = hasher(...args);
if (_hop.call(memo, key)) {
_back(() => callback(...memo[key]));
} else if (_hop.call(queues, key)) {
queues[key].push(callback);
} else {
queues[key] = [callback];
fn(...args, (...args2) => {
memo[key] = args2;
const q = queues[key];
delete queues[key];
q.forEach((item) => {
item(...args2);
});
});
}
};
memoized.memo = memo;
memoized.unmemoized = fn;
return memoized;
};
/**
* @name unmemoize
* @static
* @method
* @param {Function} fn
* @return {Function} wrapped function
*/
const unmemoize = (fn) => {
/**
* @param {...any} args
* @return {any}
*/
const _wrappedFn = (...args) => (fn.unmemoized || fn)(...args);
return _wrappedFn;
};
/**
* @name retry
* @static
* @method
* @alias retryable
* @param {Object|Array|Iterable} obj
* @param {Function} iterator
* @param {Function} [callback]
* @return {any}
*/
const retry = function (obj, iterator, callback) {
if (arguments.length < 1 || arguments.length > 3) {
throw new Error('Invalid arguments - must be either (task), (task, callback), (times, task) or (times, task, callback)');
}
/*eslint-disable no-param-reassign*/
let error,
times,
errorFilter,
interval = 0,
intervalFunc = () => interval;
if (_isFunction(obj)) {
callback = iterator;
iterator = obj;
times = 5;
} else if (_isObject(obj)) {
times = parseInt(obj.times) || 5;
if (_isFunction(obj.interval))
intervalFunc = obj.interval;
else
interval = parseInt(obj.interval) || interval;
if (obj.errorFilter)
errorFilter = obj.errorFilter;
} else {
times = parseInt(times) || 5;
}
/*eslint-enable no-param-reassign*/
const task = (wcb, data) => {
let _data = data;
_eachLimit(Array(times), 1, (item, key, cb) => {
run((_cb) => iterator(_cb, _data), (err, res) => {
error = err || null;
_data = {
err: error,
result: res
};
if (err && key < times - 1) {
if (errorFilter && !errorFilter(err))
cb(true);
else {
// eslint-disable-next-line sonarjs/no-extra-arguments
let int = intervalFunc(key + 1);
if (int > 0) {
setTimeout(cb, int);
} else {
cb();
}
}
} else {
cb(!err);
}
});
}, () => {
(wcb || callback || noop)(error, _data);
});
};
return callback ? task() : task;
};
/**
* @name transform
* @static
* @method
* @param {Array} arr
* @param {any} memo
* @param {Function} task
* @param {Function} [callback]
*/
const transform = function (arr, memo, task, callback) {
/*eslint-disable no-param-reassign*/
if (arguments.length <= 3) {
callback = task;
task = memo;
memo = _isArray(arr) ? [] : {};
}
callback = _once(callback);
/*eslint-enable no-param-reassign*/
_eachLimit(arr, _MAX, (item, key, cb) => {
run((_cb) => task(memo, item, key, _cb), cb);
}, (err) => callback(err, memo));
};
/**
* @name reflect
* @static
* @method
* @param {Function} iterator
* @return {Function}
*/
const reflect = (iterator) => {
/**
* @param {...any} args
* @param {Function} callback
*/
return function _wrappedFn(...args) {
const callback = args[args.length - 1];
args[args.length - 1] = function _wrappedCallback(error, ...args2) {
if (error) {
callback(null, {
error
});
} else {
let value;
if (args2.length) {
value = args2.length === 1 ? args2[0] : args2;
} else {
value = null;
}
callback(null, {
value
});
}
};
const res = iterator.apply(this, args);
if (_isAsyncFunction(iterator) || _isPromiseLike(res)) {
res.then((value) => {
back(callback, null, {
value
});
}, (error) => {
back(callback, null, {
error
});
});
}
};
};
/**
* @name reflectAll
* @static
* @method
* @param {Function[]} tasks
* @return {Array}
*/
const reflectAll = (tasks) => {
if (_isArray(tasks)) {
return tasks.map(reflect);
}
let res = {};
_keys(tasks).forEach((key) => {
res[key] = reflect(tasks[key]);
});
return res;
};
/**
* @name race
* @static
* @method
* @param {Array} tasks
* @param {Function} callback
*/
const race = (tasks, callback) => {
if (!_isArray(tasks)) {
_throwError(_typedErrors[0], callback);
return;
}
if (!tasks.length) {
callback();
} else {
const _callback = _once(callback);
tasks.forEach((task) => {
task(_callback);
});
}
};
/**
* @name tryEach
* @static
* @method
* @param {Object|Array|Iterable} obj
* @param {Function} [callback]
*/
const tryEach = (obj, callback = noop) => {
if (!_isObject(obj)) {
_throwError(_typedErrors[0], callback);
return;
}
let error = null,
res;
_eachLimit(obj, 1, (item, key, cb) => {
run(item, (err, ...args) => {
res = args.length <= 1 ? args[0] : args;
error = err;
cb(!err);
});
}, () => {
callback(error, res);
});
};
/**
* @name queue
* @static
* @method
* @param {Function} worker
* @param {number} [threads]
* @return {Queue}
*/
const queue = (worker, threads) => {
/**
* @property {Array} tasks
* @property {number} concurrency
* @property {number} buffer
* @property {boolean} started
* @property {boolean} paused
*/
return new Queue(worker, threads);
};
/**
* @name priorityQueue
* @static
* @method
* @param {Function} worker
* @param {number} [threads]
* @return {PriorityQueue}
*/
const priorityQueue = (worker, threads) => {
/**
* @property {Array} tasks
* @property {number} concurrency
* @property {number} buffer
* @property {boolean} started
* @property {boolean} paused
*/
return new PriorityQueue(worker, threads);
};
/**
* @name cargo
* @static
* @method
* @param {Function} worker
* @param {number} [payload]
* @return {CargoQueue}
*/
const cargo = (worker, payload) => {
/**
* @property {Array} tasks
* @property {number} concurrency
* @property {number} buffer
* @property {boolean} started
* @property {boolean} paused
* @property {number} payload
*/
return new CargoQueue(worker, payload);
};
/**
* @name times
* @static
* @method
* @param {number} t - times
* @param {Function} iterator
* @param {Function} [callback]
*/
const times = (t, iterator, callback) => {
_times(t, _MAX, iterator, callback);
};
/**
* @name timesLimit
* @static
* @method
* @param {number} t - times
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const timesLimit = (t, limit, iterator, callback) => {
_times(t, limit, iterator, callback);
};
/**
* @name timesSeries
* @static
* @method
* @param {number} t - times
* @param {Function} iterator
* @param {Function} [callback]
*/
const timesSeries = (t, iterator, callback) => {
_times(t, 1, iterator, callback);
};
/**
* @name detect
* @static
* @method
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const detect = (arr, iterator, callback) => {
_detect(arr, _MAX, iterator, callback);
};
/**
* @name detectLimit
* @static
* @method
* @param {Array} arr
* @param {number} limit
* @param {Function} iterator
* @param {Function} [callback]
*/
const detectLimit = (arr, limit, iterator, callback) => {
_detect(arr, limit, iterator, callback);
};
/**
* @name detectSeries
* @static
* @method
* @param {Array} arr
* @param {Function} iterator
* @param {Function} [callback]
*/
const detectSeries = (arr, iterator, callback) => {
_detect(arr, 1, iterator, callback);
};
const applyEach = _applyEach(_MAX);
const applyEachSeries = _applyEach(1);
const safe = {
noop,
nextTick,
back,
setImmediate: back,
yield: back,
apply,
async,
inherits,
args: argToArr,
ensureAsync,
constant,
result,
sure_result,
trap_sure_result: sure_result,
sure,
trap_sure: sure,
sure_spread,
spread,
trap,
wrap,
run,
each: forEach,
forEach,
eachLimit,
forEachLimit: eachLimit,
eachSeries,
forEachSeries: eachSeries,
eachOf,
forEachOf: eachOf,
eachOfLimit,
forEachOfLimit: eachOfLimit,
eachOfSeries,
forEachOfSeries: eachOfSeries,
map,
mapLimit,
mapSeries,
groupBy,
groupByLimit,
groupBySeries,
mapValues,
mapValuesLimit,
mapValuesSeries,
concat,
concatLimit,
concatSeries,
sortBy,
filter,
select: filter,
filterLimit,
selectLimit: filterLimit,
filterSeries,
selectSeries: filterSeries,
reject,
rejectLimit,
rejectSeries,
waterfall,
series,
parallel,
parallelLimit,
auto,
whilst,
doWhilst,
during,
doDuring,
until,
doUntil,
forever,
reduce,
inject: reduce,
foldl: reduce,
reduceRight,
foldr: reduceRight,
queue,
priorityQueue,
cargo,
retry,
retryable: retry,
times,
timesLimit,
timesSeries,
detect,
detectLimit,
detectSeries,
some,
any: some,
someLimit,
anyLimit: someLimit,
someSeries,
anySeries: someSeries,
every,
all: every,
everyLimit,
allLimit: everyLimit,
everySeries,
allSeries: everySeries,
applyEach,
applyEachSeries,
asyncify,
wrapSync: asyncify,
memoize,
unmemoize,
transform,
reflect,
reflectAll,
race,
tryEach
};
exports['de