-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
161 lines (145 loc) · 3.95 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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/******************************************************************************/
/**
* Reduce anything in Co-like manner
* @module co-reduce-any
* @author Lukasz A.J. Wrona <[email protected]>
* @license MIT
*/
/******************************************************************************/
"use strict"
var typical = require("typical")
var Stream = require("stream")
/******************************************************************************/
var isPromise = typical.isPromise
var isObject = typical.isObject
var isIterable = typical.isIterable
var next = Object.freeze({ })
function* enumerateIterable(collection) {
var elem
var index = 0
for (elem of collection) {
yield [ index, elem ]
index += 1
}
}
// Enumerate map 1:1
function* enumerateMap(map) {
var pair
for (pair of map) {
yield pair
}
}
// Enumerate object literals
function* enumerateObject(object) {
var key
for (key in object) {
yield [ key, object[key] ]
}
}
// Inspired by Python's enumerate
function enumerate(collection) {
if (isObject(collection)) {
if (collection instanceof Map) {
return enumerateMap(collection)
} else if (isIterable(collection)) {
return enumerateIterable(collection)
} else {
return enumerateObject(collection)
}
} else {
throw new TypeError("Object cannot be enumerated")
}
}
function then(value, proc) {
return isPromise(value) ? value.then(proc) : proc(value)
}
function genStep(gen, chunk, err) {
var done, state, value
if (err) {
state = gen.throw(err)
} else {
state = gen.next(chunk)
}
done = state.done
value = state.value
if (done) {
return value
} else if (value === next) {
return next
} else if (isPromise(value)) {
return value.catch(function (err) {
return genStep(gen, undefined, err)
})
.then(function (value) {
return genStep(gen, value)
})
} else {
return genStep(gen, value)
}
}
function reduceStream(stream, generator) {
return new Promise(function (resolve, reject) {
var gen = generator(next)
var promise = Promise.resolve(genStep(gen))
.then(function (result) {
if (result !== next) {
resolve(result)
}
})
var i = 0
stream.on("data", function (chunk) {
stream.pause()
promise = promise.then(function () {
return genStep(gen, [ i, chunk ])
})
.then(function (result) {
if (result === next) {
i++
stream.resume()
} else {
resolve(result)
}
})
.catch(reject)
})
stream.on("error", reject)
stream.on("end", function () {
promise = promise.then(function () {
return genStep(gen)
})
.then(resolve, reject)
})
})
}
function _reduceGen(inGen, outGen) {
var state = inGen.next()
return then(genStep(outGen, state.value), function (value) {
if (state.done) {
return then(genStep(outGen), function () {
return value
})
} else if (value === next) {
return _reduceGen(inGen, outGen)
} else {
return value
}
})
}
function reduceGen(inGen, generator) {
var outGen = generator(next)
return then(genStep(outGen), function (result) {
if (result === next) {
return _reduceGen(inGen, outGen)
} else {
return result
}
})
}
function reduceAny(collection, generator) {
if (collection instanceof Stream) {
return reduceStream(collection, generator)
} else {
return reduceGen(enumerate(collection), generator)
}
}
module.exports = reduceAny