-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.js
102 lines (86 loc) · 2.44 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
'use strict';
function isFunction(v) {
return typeof v === 'function';
}
function isThenable(v) {
return typeof v === 'object' && typeof v.then === 'function';
}
function isGeneratorFunction(v) {
return isFunction(v) && v.constructor.name === 'GeneratorFunction';
}
function isObject(o) {
return o instanceof Object;
}
function isGenerator(v) {
return isObject(v) && isFunction(v.next) && isFunction(v.throw);
}
function thenableToFunction(t) {
return cb => t.then(v => cb(null, v), err => cb(err));
}
function generatorToFunction(gen) {
return cb => advance(gen, cb);
}
function valueToFunction(v) {
return isGeneratorFunction(v) ? generatorToFunction(v()) :
isFunction(v) ? v :
isGenerator(v) ? generatorToFunction(v) :
isThenable(v) ? thenableToFunction(v) :
Array.isArray(v) ? arrayToFunction(v) :
isObject(v) ? objectToFunction(v) :
cb => process.nextTick(() => cb(null, v));
}
function arrayToFunction(arr) {
return iterableToFunction(
() => new Array(arr.length),
cb => arr.forEach(cb),
count => count === arr.length);
}
function objectToFunction(o) {
const keys = Object.keys(o);
return iterableToFunction(
() => Object.assign({}, o),
cb => keys.forEach(k => cb(o[k], k)),
count => count === keys.length);
}
function iterableToFunction(createDest, iterate, hasFinished) {
return function (cb) {
const dest = createDest();
let count = 0;
let stopIteration = false;
iterate(function (e, i) {
valueToFunction(e)(function (err, value) {
if (stopIteration) {
return;
}
dest[i] = value;
count += 1;
if (err || hasFinished(count)) {
cb(err, dest);
stopIteration = true;
}
});
});
};
}
function advance(gen, cb, err, result) {
try {
const r = err ? gen.throw(err) : gen.next(result);
return r.done ? cb(null, r.value) :
valueToFunction(r.value)((fnErr, fnResult) => advance(gen, cb, fnErr, fnResult));
} catch (genErr) {
return cb(genErr);
}
}
class ErrorGenerator {
next() {
throw new TypeError('genOrFn must be a generator or a generator function');
}
}
function few(genOrFn, cb) {
advance(
isGenerator(genOrFn) ? genOrFn :
isGeneratorFunction(genOrFn) ? genOrFn() :
new ErrorGenerator(),
isFunction(cb) ? cb : err => { if (err) process.nextTick(() => { throw err; }); });
}
module.exports = few;