ig-types 6.14.1 → 6.15.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Array.js +39 -15
- package/Promise.js +170 -41
- package/README.md +130 -14
- package/generator.js +240 -51
- package/package.json +1 -1
package/Array.js
CHANGED
|
@@ -24,6 +24,9 @@ var STOP =
|
|
|
24
24
|
module.STOP =
|
|
25
25
|
object.STOP
|
|
26
26
|
|
|
27
|
+
var stoppable =
|
|
28
|
+
module.stoppable =
|
|
29
|
+
generator.stoppable
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
//---------------------------------------------------------------------
|
|
@@ -139,7 +142,8 @@ var makeChunkIter = function(iter, wrapper){
|
|
|
139
142
|
try {
|
|
140
143
|
// handle iteration...
|
|
141
144
|
res.push(
|
|
142
|
-
val = (chunk = chunks.shift())
|
|
145
|
+
val = (chunk = chunks.shift())
|
|
146
|
+
[iter](_wrapper, ...rest))
|
|
143
147
|
// handle chunk...
|
|
144
148
|
postChunk
|
|
145
149
|
&& postChunk.call(that,
|
|
@@ -211,6 +215,7 @@ object.Mixin('ArrayMixin', 'soft', {
|
|
|
211
215
|
// done...
|
|
212
216
|
: [] },
|
|
213
217
|
|
|
218
|
+
// XXX add handler function support -- a-la generator.js'
|
|
214
219
|
iter: function*(lst=[]){
|
|
215
220
|
yield* lst.iter() },
|
|
216
221
|
})
|
|
@@ -319,9 +324,12 @@ object.Mixin('ArrayProtoMixin', 'soft', {
|
|
|
319
324
|
// NOTE: order is preserved...
|
|
320
325
|
unique: function(normalize){
|
|
321
326
|
return normalize ?
|
|
322
|
-
[...new Map(this
|
|
323
|
-
|
|
324
|
-
|
|
327
|
+
[...new Map(this
|
|
328
|
+
.map(function(e){
|
|
329
|
+
return [normalize(e), e] }))
|
|
330
|
+
.values()]
|
|
331
|
+
// NOTE: we are calling .compact() here to avoid creating
|
|
332
|
+
// undefined items from empty slots in sparse arrays...
|
|
325
333
|
: [...new Set(this.compact())] },
|
|
326
334
|
tailUnique: function(normalize){
|
|
327
335
|
return this
|
|
@@ -336,8 +344,8 @@ object.Mixin('ArrayProtoMixin', 'soft', {
|
|
|
336
344
|
// self to other (internal) while match compares two entities
|
|
337
345
|
// externally.
|
|
338
346
|
// XXX not sure if we need the destinction in name, will have to
|
|
339
|
-
// come back to this when refactoring diff.js -- all three
|
|
340
|
-
// to be similar...
|
|
347
|
+
// come back to this when refactoring diff.js -- all three
|
|
348
|
+
// have to be similar...
|
|
341
349
|
cmp: function(other){
|
|
342
350
|
if(this === other){
|
|
343
351
|
return true }
|
|
@@ -353,7 +361,8 @@ object.Mixin('ArrayProtoMixin', 'soft', {
|
|
|
353
361
|
// NOTE: this will ignore order and repeating elments...
|
|
354
362
|
setCmp: function(other){
|
|
355
363
|
return this === other
|
|
356
|
-
|| (new Set([...this, ...other])).length
|
|
364
|
+
|| (new Set([...this, ...other])).length
|
|
365
|
+
== (new Set(this)).length },
|
|
357
366
|
|
|
358
367
|
// Sort as the other array...
|
|
359
368
|
//
|
|
@@ -369,12 +378,13 @@ object.Mixin('ArrayProtoMixin', 'soft', {
|
|
|
369
378
|
// This will sort the intersecting items in the head keeping the rest
|
|
370
379
|
// of the items in the same relative order...
|
|
371
380
|
//
|
|
372
|
-
// NOTE: if an item is in the array multiple times only the first
|
|
373
|
-
// is used...
|
|
381
|
+
// NOTE: if an item is in the array multiple times only the first
|
|
382
|
+
// index is used...
|
|
374
383
|
//
|
|
375
384
|
// XXX should this extend/patch .sort(..)???
|
|
376
|
-
// ...currently do not see a clean way to do this without
|
|
377
|
-
// and replacing Array or directly re-wrapping
|
|
385
|
+
// ...currently do not see a clean way to do this without
|
|
386
|
+
// extending and replacing Array or directly re-wrapping
|
|
387
|
+
// .sort(..)...
|
|
378
388
|
sortAs: function(other, place='head'){
|
|
379
389
|
place = place == 'tail' ? -1 : 1
|
|
380
390
|
// NOTE: the memory overhead here is better than the time overhead
|
|
@@ -441,8 +451,8 @@ object.Mixin('ArrayProtoMixin', 'soft', {
|
|
|
441
451
|
|
|
442
452
|
// Convert an array to a map...
|
|
443
453
|
//
|
|
444
|
-
// This is similar to Array.prototype.toKeys(..) but does not
|
|
445
|
-
// value type to string.
|
|
454
|
+
// This is similar to Array.prototype.toKeys(..) but does not
|
|
455
|
+
// restrict value type to string.
|
|
446
456
|
//
|
|
447
457
|
// Format:
|
|
448
458
|
// Map([
|
|
@@ -482,8 +492,22 @@ object.Mixin('ArrayProtoMixin', 'soft', {
|
|
|
482
492
|
// -> iterator
|
|
483
493
|
//
|
|
484
494
|
// XXX should this take an argument and be like map??
|
|
485
|
-
|
|
486
|
-
|
|
495
|
+
// XXX this should handle throwing STOP!!!
|
|
496
|
+
// ...might also ne a good idea to isolate the STOP mechanics
|
|
497
|
+
// into a spearate module/package...
|
|
498
|
+
iter: stoppable(function*(handler=undefined){
|
|
499
|
+
if(handler){
|
|
500
|
+
var i = 0
|
|
501
|
+
for(var e of this){
|
|
502
|
+
var res = handler.call(this, e, i++)
|
|
503
|
+
// treat non-iterables as single elements...
|
|
504
|
+
if(typeof(res) == 'object'
|
|
505
|
+
&& Symbol.iterator in res){
|
|
506
|
+
yield* res
|
|
507
|
+
} else {
|
|
508
|
+
yield res } }
|
|
509
|
+
} else {
|
|
510
|
+
yield* this }}),
|
|
487
511
|
|
|
488
512
|
|
|
489
513
|
// Stoppable iteration...
|
package/Promise.js
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* Promise.iter(seq)
|
|
6
6
|
* <promise>.iter()
|
|
7
7
|
* Iterable promise object.
|
|
8
|
-
* Similar to Promise.all(..) but adds basic iterator
|
|
9
|
-
* API and will resolve the items as they are ready (resolved).
|
|
8
|
+
* Similar to Promise.all(..) but adds basic iterator API.
|
|
10
9
|
*
|
|
11
10
|
* Promise.interactive(handler)
|
|
12
11
|
* Interactive promise object.
|
|
@@ -31,6 +30,8 @@
|
|
|
31
30
|
|
|
32
31
|
var object = require('ig-object')
|
|
33
32
|
|
|
33
|
+
//var generator = require('./generator')
|
|
34
|
+
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
//---------------------------------------------------------------------
|
|
@@ -39,16 +40,6 @@ var object = require('ig-object')
|
|
|
39
40
|
// Like Promise.all(..) but adds ability to iterate through results
|
|
40
41
|
// via generators .map(..)/.reduce(..) and friends...
|
|
41
42
|
//
|
|
42
|
-
// NOTE: it would be nice to support throwing STOP (XXX) from the iterable
|
|
43
|
-
// promise but...
|
|
44
|
-
// - this is more complicated than simply using .smap(..) instead
|
|
45
|
-
// of .map(..) because the list can contain async promises...
|
|
46
|
-
// ...would need to wrap each .then(..) call in try-catch and
|
|
47
|
-
// manually handle the stop...
|
|
48
|
-
// ...then there's a question of derivative iterators etc.
|
|
49
|
-
// - another issue here is that the stop would happen in order of
|
|
50
|
-
// execution and not order of elements...
|
|
51
|
-
// XXX though stopping within a single level might be useful...
|
|
52
43
|
// NOTE: the following can not be implemented here:
|
|
53
44
|
// .splice(..) - can't both modify and return
|
|
54
45
|
// a result...
|
|
@@ -68,18 +59,19 @@ var object = require('ig-object')
|
|
|
68
59
|
// back to the complex IterablePromise...
|
|
69
60
|
//
|
|
70
61
|
// XXX how do we handle errors/rejections???
|
|
62
|
+
// ...mostly the current state is OK, but need more testing...
|
|
63
|
+
// XXX add support for async generators...
|
|
71
64
|
//
|
|
72
65
|
|
|
73
|
-
// XXX should these be exported???
|
|
74
66
|
var iterPromiseProxy =
|
|
75
|
-
|
|
67
|
+
module.iterPromiseProxy =
|
|
76
68
|
function(name){
|
|
77
69
|
return function(...args){
|
|
78
70
|
return this.constructor(
|
|
79
71
|
this.then(function(lst){
|
|
80
72
|
return lst[name](...args) })) } }
|
|
81
73
|
var promiseProxy =
|
|
82
|
-
|
|
74
|
+
module.promiseProxy =
|
|
83
75
|
function(name){
|
|
84
76
|
return async function(...args){
|
|
85
77
|
return (await this)[name](...args) } }
|
|
@@ -87,6 +79,10 @@ function(name){
|
|
|
87
79
|
var IterablePromise =
|
|
88
80
|
module.IterablePromise =
|
|
89
81
|
object.Constructor('IterablePromise', Promise, {
|
|
82
|
+
get STOP(){
|
|
83
|
+
return Array.STOP },
|
|
84
|
+
|
|
85
|
+
}, {
|
|
90
86
|
// packed array...
|
|
91
87
|
//
|
|
92
88
|
// Holds promise state.
|
|
@@ -100,14 +96,14 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
100
96
|
// ]
|
|
101
97
|
//
|
|
102
98
|
// This format has several useful features:
|
|
103
|
-
// - concatenating packed
|
|
99
|
+
// - concatenating packed lists results in a packed list
|
|
104
100
|
// - adding an iterable promise (as-is) into a packed list results
|
|
105
101
|
// in a packed list
|
|
106
102
|
//
|
|
107
103
|
// NOTE: in general iterable promises are implicitly immutable, so
|
|
108
|
-
// it is not recomended to ever edit this
|
|
109
|
-
// NOTE: we are not
|
|
110
|
-
// responsibly extend the code.
|
|
104
|
+
// it is not recomended to ever edit this in-place...
|
|
105
|
+
// NOTE: we are not isolating or "protecting" any internals to
|
|
106
|
+
// enable users to responsibly extend the code.
|
|
111
107
|
__packed: null,
|
|
112
108
|
|
|
113
109
|
// low-level .__packed handlers/helpers...
|
|
@@ -115,6 +111,20 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
115
111
|
// NOTE: these can be useful for debugging and extending...
|
|
116
112
|
//
|
|
117
113
|
// pack and oprionally transform/handle an array (sync)...
|
|
114
|
+
//
|
|
115
|
+
// NOTE: if 'types/Array' is imported this will support throwing STOP
|
|
116
|
+
// from the handler.
|
|
117
|
+
// Due to the async nature of promises though the way stops are
|
|
118
|
+
// handled may be unpredictable -- the handlers can be run out
|
|
119
|
+
// of order, as the nested promises resolve and thus throwing
|
|
120
|
+
// stop will stop the handlers not yet run and not the next
|
|
121
|
+
// handlers in sequence.
|
|
122
|
+
// XXX EXPEREMENTAL: STOP...
|
|
123
|
+
// XXX add support for async generators...
|
|
124
|
+
// ...an async generator is not "parallel", i.e. intil one
|
|
125
|
+
// returned promise is resolved the generator blocks (will not
|
|
126
|
+
// advance)...
|
|
127
|
+
// ...can we feed out a results one by one???
|
|
118
128
|
__pack: function(list, handler=undefined){
|
|
119
129
|
var that = this
|
|
120
130
|
// handle iterable promise list...
|
|
@@ -131,6 +141,57 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
131
141
|
handler = handler
|
|
132
142
|
?? function(elem){
|
|
133
143
|
return [elem] }
|
|
144
|
+
|
|
145
|
+
//* XXX EXPEREMENTAL: STOP...
|
|
146
|
+
var stoppable = false
|
|
147
|
+
var stop = false
|
|
148
|
+
var map = 'map'
|
|
149
|
+
var pack = function(){
|
|
150
|
+
return [list].flat()
|
|
151
|
+
[map](function(elem){
|
|
152
|
+
return elem && elem.then ?
|
|
153
|
+
(stoppable ?
|
|
154
|
+
// stoppable -- need to handle stop async...
|
|
155
|
+
elem
|
|
156
|
+
.then(function(res){
|
|
157
|
+
return !stop ?
|
|
158
|
+
handler(res)
|
|
159
|
+
: [] })
|
|
160
|
+
// NOTE: we are using .catch(..) here
|
|
161
|
+
// instead of directly passing the
|
|
162
|
+
// error handler to be able to catch
|
|
163
|
+
// the STOP from the handler...
|
|
164
|
+
.catch(handleSTOP)
|
|
165
|
+
// non-stoppable...
|
|
166
|
+
: elem.then(handler))
|
|
167
|
+
: elem instanceof Array ?
|
|
168
|
+
handler(elem)
|
|
169
|
+
// NOTE: we keep things that do not need protecting
|
|
170
|
+
// from .flat() as-is...
|
|
171
|
+
: !handle ?
|
|
172
|
+
elem
|
|
173
|
+
: handler(elem) }) }
|
|
174
|
+
|
|
175
|
+
// pack (stoppable)...
|
|
176
|
+
if(!!this.constructor.STOP){
|
|
177
|
+
stoppable = true
|
|
178
|
+
map = 'smap'
|
|
179
|
+
var handleSTOP = function(err){
|
|
180
|
+
stop = err
|
|
181
|
+
if(err === that.constructor.STOP
|
|
182
|
+
|| err instanceof that.constructor.STOP){
|
|
183
|
+
return 'value' in err ?
|
|
184
|
+
err.value
|
|
185
|
+
: [] }
|
|
186
|
+
throw err }
|
|
187
|
+
try{
|
|
188
|
+
return pack()
|
|
189
|
+
}catch(err){
|
|
190
|
+
return handleSTOP(err) } }
|
|
191
|
+
|
|
192
|
+
// pack (non-stoppable)...
|
|
193
|
+
return pack() },
|
|
194
|
+
/*/
|
|
134
195
|
return [list].flat()
|
|
135
196
|
.map(function(elem){
|
|
136
197
|
return elem && elem.then ?
|
|
@@ -143,6 +204,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
143
204
|
: !handle ?
|
|
144
205
|
elem
|
|
145
206
|
: handler(elem) }) },
|
|
207
|
+
//*/
|
|
146
208
|
// transform/handle packed array (sync)...
|
|
147
209
|
__handle: function(list, handler=undefined){
|
|
148
210
|
var that = this
|
|
@@ -159,13 +221,21 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
159
221
|
// NOTE: since each section of the packed .__array is the same
|
|
160
222
|
// structure as the input we'll use .__pack(..) to handle
|
|
161
223
|
// them, this also keeps all the handling code in one place.
|
|
224
|
+
//* XXX EXPEREMENTAL: STOP...
|
|
225
|
+
var map = !!this.constructor.STOP ?
|
|
226
|
+
'smap'
|
|
227
|
+
: 'map'
|
|
228
|
+
return list[map](function(elem){
|
|
229
|
+
/*/
|
|
162
230
|
return list.map(function(elem){
|
|
231
|
+
//*/
|
|
163
232
|
return elem instanceof Array ?
|
|
164
233
|
that.__pack(elem, handler)
|
|
165
234
|
: elem instanceof Promise ?
|
|
166
235
|
that.__pack(elem, handler)
|
|
167
|
-
|
|
168
|
-
|
|
236
|
+
//.then(function(elem){
|
|
237
|
+
.then(function([elem]){
|
|
238
|
+
return elem })
|
|
169
239
|
: [handler(elem)] })
|
|
170
240
|
.flat() },
|
|
171
241
|
// unpack array (async)...
|
|
@@ -224,6 +294,8 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
224
294
|
.then(function(){
|
|
225
295
|
return res }) },
|
|
226
296
|
|
|
297
|
+
// XXX .chain(..) -- see generator.chain(..)
|
|
298
|
+
|
|
227
299
|
flat: function(depth=1){
|
|
228
300
|
return this.constructor(this,
|
|
229
301
|
function(e){
|
|
@@ -280,12 +352,6 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
280
352
|
return this.constructor([elem])
|
|
281
353
|
.concat(this) },
|
|
282
354
|
|
|
283
|
-
|
|
284
|
-
// XXX thses need to stop once an element is found so we cant simply
|
|
285
|
-
// use .map(..) or .reduce(..)...
|
|
286
|
-
// XXX .find(func) / .findIndex(func)
|
|
287
|
-
|
|
288
|
-
|
|
289
355
|
// proxy methods...
|
|
290
356
|
//
|
|
291
357
|
// These require the whole promise to resolve to trigger.
|
|
@@ -300,6 +366,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
300
366
|
var list = this.__packed
|
|
301
367
|
return ((i != 0 && i != -1)
|
|
302
368
|
|| list instanceof Promise
|
|
369
|
+
// XXX not sure if this is correct...
|
|
303
370
|
|| list.at(i) instanceof Promise) ?
|
|
304
371
|
(await this).at(i)
|
|
305
372
|
// NOTE: we can only reason about first/last explicit elements,
|
|
@@ -316,29 +383,91 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
316
383
|
|
|
317
384
|
// NOTE: unlike .reduce(..) this needs the parent fully resolved
|
|
318
385
|
// to be able to iterate from the end.
|
|
319
|
-
// XXX ???
|
|
386
|
+
// XXX is it faster to do .reverse().reduce(..) ???
|
|
320
387
|
reduceRight: promiseProxy('reduceRight'),
|
|
321
388
|
|
|
322
389
|
// NOTE: there is no way we can do a sync generator returning
|
|
323
|
-
// promises for values because any promise in .__packed makes
|
|
324
|
-
// value count/index non-deterministic...
|
|
390
|
+
// promises for values because any promise in .__packed makes
|
|
391
|
+
// the value count/index non-deterministic...
|
|
325
392
|
sort: iterPromiseProxy('sort'),
|
|
326
|
-
// XXX we could have a special-case here for .slice()/slice(0, -1)
|
|
327
|
-
// and possibly othets, should we???
|
|
328
393
|
slice: iterPromiseProxy('slice'),
|
|
329
394
|
|
|
330
395
|
entries: iterPromiseProxy('entries'),
|
|
331
396
|
keys: iterPromiseProxy('keys'),
|
|
332
|
-
// XXX we could possibly make this better via .map(..)
|
|
333
397
|
values: iterPromiseProxy('values'),
|
|
334
398
|
|
|
335
399
|
indexOf: promiseProxy('indexOf'),
|
|
336
400
|
lastIndexOf: promiseProxy('lastIndexOf'),
|
|
337
401
|
includes: promiseProxy('includes'),
|
|
338
402
|
|
|
403
|
+
//
|
|
404
|
+
// .find(<func>)
|
|
405
|
+
// .find(<func>, 'value')
|
|
406
|
+
// -> <promise>(<value>)
|
|
407
|
+
//
|
|
408
|
+
// .find(<func>, 'result')
|
|
409
|
+
// -> <promise>(<result>)
|
|
410
|
+
//
|
|
411
|
+
// .find(<func>, 'bool')
|
|
412
|
+
// -> <promise>(<bool>)
|
|
413
|
+
//
|
|
414
|
+
// NOTE: this is slightly different to Array's .find(..) in that it
|
|
415
|
+
// accepts the result value enabling returning both the value
|
|
416
|
+
// itself ('value', default), the test function's result
|
|
417
|
+
// ('result') or true/false ('bool') -- this is added to be
|
|
418
|
+
// able to distinguish between the undefined as a stored value
|
|
419
|
+
// and undefined as a "nothing found" result.
|
|
420
|
+
// NOTE: I do not get how essentially identical methods .some(..)
|
|
421
|
+
// and .find(..) got added to JS's Array...
|
|
422
|
+
// the only benefit is that .some(..) handles undefined values
|
|
423
|
+
// stored in the array better...
|
|
424
|
+
// NOTE: this will return the result as soon as it's available but
|
|
425
|
+
// it will not stop the created but unresolved at the time
|
|
426
|
+
// promises from executing, this is both good and bad:
|
|
427
|
+
// + it will not break other clients waiting for promises
|
|
428
|
+
// to resolve...
|
|
429
|
+
// - if no clients are available this can lead to wasted
|
|
430
|
+
// CPU time...
|
|
431
|
+
find: async function(func, result='value'){
|
|
432
|
+
var that = this
|
|
433
|
+
// NOTE: not using pure await here as this is simpler to actually
|
|
434
|
+
// control the moment the resulting promise resolves without
|
|
435
|
+
// the need for juggling state...
|
|
436
|
+
return new Promise(function(resolve, reject){
|
|
437
|
+
var resolved = false
|
|
438
|
+
that.map(function(elem){
|
|
439
|
+
var res = func(elem)
|
|
440
|
+
if(res){
|
|
441
|
+
resolved = true
|
|
442
|
+
resolve(
|
|
443
|
+
result == 'bool' ?
|
|
444
|
+
true
|
|
445
|
+
: result == 'result' ?
|
|
446
|
+
res
|
|
447
|
+
: elem)
|
|
448
|
+
// XXX EXPEREMENTAL: STOP...
|
|
449
|
+
// NOTE: we do not need to throw STOP here
|
|
450
|
+
// but it can prevent some overhead...
|
|
451
|
+
if(that.constructor.STOP){
|
|
452
|
+
throw that.constructor.STOP } } })
|
|
453
|
+
.then(function(){
|
|
454
|
+
resolved
|
|
455
|
+
|| resolve(
|
|
456
|
+
result == 'bool' ?
|
|
457
|
+
false
|
|
458
|
+
: undefined) }) }) },
|
|
459
|
+
findIndex: promiseProxy('findIndex'),
|
|
460
|
+
|
|
461
|
+
// NOTE: this is just a special-case of .find(..)
|
|
462
|
+
some: async function(func){
|
|
463
|
+
return this.find(func, 'bool') },
|
|
339
464
|
every: promiseProxy('every'),
|
|
340
|
-
|
|
341
|
-
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
// this is defined globally as Promise.prototype.iter(..)
|
|
468
|
+
//
|
|
469
|
+
// for details see: PromiseMixin(..) below...
|
|
470
|
+
//iter: function(handler=undefined){ ... },
|
|
342
471
|
|
|
343
472
|
|
|
344
473
|
// promise api...
|
|
@@ -368,12 +497,6 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
368
497
|
: p },
|
|
369
498
|
|
|
370
499
|
|
|
371
|
-
// this is defined globally as Promise.prototype.iter(.,)
|
|
372
|
-
//
|
|
373
|
-
// for details see: PromiseMixin(..) below...
|
|
374
|
-
//iter: function(handler=undefined){ ... },
|
|
375
|
-
|
|
376
|
-
|
|
377
500
|
// constructor...
|
|
378
501
|
//
|
|
379
502
|
// Promise.iter([ .. ])
|
|
@@ -394,6 +517,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
394
517
|
// items...
|
|
395
518
|
// XXX we can make the index a promise, then if the client needs
|
|
396
519
|
// the value they can wait for it...
|
|
520
|
+
// ...this may be quite an overhead...
|
|
397
521
|
//
|
|
398
522
|
//
|
|
399
523
|
// Special cases useful for extending this constructor...
|
|
@@ -406,6 +530,10 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
406
530
|
// Promise.iter(false)
|
|
407
531
|
// -> iterable-promise
|
|
408
532
|
//
|
|
533
|
+
//
|
|
534
|
+
// NOTE: if 'types/Array' is imported this will support throwing STOP,
|
|
535
|
+
// for more info see notes for .__pack(..)
|
|
536
|
+
// XXX EXPEREMENTAL: STOP...
|
|
409
537
|
__new__: function(_, list, handler){
|
|
410
538
|
// instance...
|
|
411
539
|
var promise
|
|
@@ -526,6 +654,7 @@ object.Constructor('InteractivePromise', Promise, {
|
|
|
526
654
|
// Cooperative promise...
|
|
527
655
|
//
|
|
528
656
|
// A promise that can be resolved/rejected externally.
|
|
657
|
+
//
|
|
529
658
|
// NOTE: normally this has no internal resolver logic...
|
|
530
659
|
//
|
|
531
660
|
|
package/README.md
CHANGED
|
@@ -78,10 +78,13 @@ Library of JavaScript type extensions, types and utilities.
|
|
|
78
78
|
- [`<promise-iter>.concat(..)`](#promise-iterconcat)
|
|
79
79
|
- [`<promise-iter>.push(..)` / `<promise-iter>.unshift(..)`](#promise-iterpush--promise-iterunshift)
|
|
80
80
|
- [`<promise-iter>.at(..)` / `<promise-iter>.first()` / `<promise-iter>.last()`](#promise-iterat--promise-iterfirst--promise-iterlast)
|
|
81
|
+
- [`<promise-iter>.some(..)` / `<promise-iter>.find(..)`](#promise-itersome--promise-iterfind)
|
|
81
82
|
- [Array proxy methods returning `<promise-iter>`](#array-proxy-methods-returning-promise-iter)
|
|
82
83
|
- [Array proxy methods returning a `<promise>`](#array-proxy-methods-returning-a-promise)
|
|
83
84
|
- [`<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally)
|
|
85
|
+
- [`promise.IterablePromise.STOP` / `promise.IterablePromise.STOP(..)`](#promiseiterablepromisestop--promiseiterablepromisestop)
|
|
84
86
|
- [Advanced handler](#advanced-handler)
|
|
87
|
+
- [Stopping the iteration](#stopping-the-iteration)
|
|
85
88
|
- [Promise proxies](#promise-proxies)
|
|
86
89
|
- [`<promise>.as(..)`](#promiseas)
|
|
87
90
|
- [`<promise-proxy>.<method>(..)`](#promise-proxymethod)
|
|
@@ -91,7 +94,7 @@ Library of JavaScript type extensions, types and utilities.
|
|
|
91
94
|
- [`generator.iter(..)`](#generatoriter)
|
|
92
95
|
- [`generator.STOP`](#generatorstop)
|
|
93
96
|
- [Generator instance iteration](#generator-instance-iteration)
|
|
94
|
-
- [`<generator>.iter()`](#generatoriter-1)
|
|
97
|
+
- [`<generator>.iter(..)`](#generatoriter-1)
|
|
95
98
|
- [`<generator>.map(..)` / `<generator>.filter(..)`](#generatormap--generatorfilter)
|
|
96
99
|
- [`<generator>.reduce(..)` / `<generator>.greduce(..)`](#generatorreduce--generatorgreduce)
|
|
97
100
|
- [`<generator>.slice(..)`](#generatorslice)
|
|
@@ -99,7 +102,6 @@ Library of JavaScript type extensions, types and utilities.
|
|
|
99
102
|
- [`<generator>.flat(..)`](#generatorflat)
|
|
100
103
|
- [`<generator>.shift()` / `<generator>.pop()` / `<generator>.gshift()` / `<generator>.gpop()`](#generatorshift--generatorpop--generatorgshift--generatorgpop)
|
|
101
104
|
- [`<generator>.unshift(..)` / `<generator>.push(..)`](#generatorunshift--generatorpush)
|
|
102
|
-
- [`<generator>.promise()`](#generatorpromise)
|
|
103
105
|
- [`<generator>.then(..)` / `<generator>.catch(..)` / `<generator>.finally(..)`](#generatorthen--generatorcatch--generatorfinally)
|
|
104
106
|
- [`<generator>.toArray()`](#generatortoarray)
|
|
105
107
|
- [Treating iterators the same as generators](#treating-iterators-the-same-as-generators)
|
|
@@ -121,6 +123,15 @@ Library of JavaScript type extensions, types and utilities.
|
|
|
121
123
|
- [`generator.produce(..)`](#generatorproduce)
|
|
122
124
|
- [Generator helpers](#generator-helpers)
|
|
123
125
|
- [`generator.stoppable(..)`](#generatorstoppable)
|
|
126
|
+
- [Async generator extensions](#async-generator-extensions)
|
|
127
|
+
- [`generator.AsyncGenerator`](#generatorasyncgenerator)
|
|
128
|
+
- [`<async-generator>.then(..)` / `<async-generator>.catch(..)` / `<async-generator>.finally(..)`](#async-generatorthen--async-generatorcatch--async-generatorfinally)
|
|
129
|
+
- [`<async-generator>.iter(..)`](#async-generatoriter)
|
|
130
|
+
- [`<async-generator>.map(..)` / `<async-generator>.filter(..)` / `<async-generator>.reduce(..)`](#async-generatormap--async-generatorfilter--async-generatorreduce)
|
|
131
|
+
- [`<async-generator>.chain(..)`](#async-generatorchain)
|
|
132
|
+
- [`<async-generator>.flat(..)`](#async-generatorflat)
|
|
133
|
+
- [`<async-generator>.concat(..)`](#async-generatorconcat)
|
|
134
|
+
- [`<async-generator>.push(..)` / `<async-generator>.unshift(..)`](#async-generatorpush--async-generatorunshift)
|
|
124
135
|
- [Containers](#containers)
|
|
125
136
|
- [`containers.UniqueKeyMap()` (`Map`)](#containersuniquekeymap-map)
|
|
126
137
|
- [`<unique-key-map>.set(..)`](#unique-key-mapset)
|
|
@@ -1674,6 +1685,46 @@ parent `<promise-iter>`.
|
|
|
1674
1685
|
|
|
1675
1686
|
XXX
|
|
1676
1687
|
|
|
1688
|
+
#### `<promise-iter>.some(..)` / `<promise-iter>.find(..)`
|
|
1689
|
+
|
|
1690
|
+
```bnf
|
|
1691
|
+
<promise-iter>.some(<func>)
|
|
1692
|
+
-> <promise>
|
|
1693
|
+
|
|
1694
|
+
<promise-iter>.find(<func>)
|
|
1695
|
+
-> <promise>
|
|
1696
|
+
```
|
|
1697
|
+
|
|
1698
|
+
The main difference between `.some(..)` and `.find(..)` is in that the `<promise>`
|
|
1699
|
+
returned from the former will resolve to either `true` or `false`, and in the later
|
|
1700
|
+
to the found value or `undefined`.
|
|
1701
|
+
|
|
1702
|
+
`.find(..)` supports an additional argument that controls what returned `<promise>`
|
|
1703
|
+
is resolved to...
|
|
1704
|
+
|
|
1705
|
+
```bnf
|
|
1706
|
+
<promise-iter>.find(<func>)
|
|
1707
|
+
<promise-iter>.find(<func>, 'value')
|
|
1708
|
+
-> <promise>
|
|
1709
|
+
|
|
1710
|
+
<promise-iter>.find(<func>, 'bool')
|
|
1711
|
+
-> <promise>
|
|
1712
|
+
|
|
1713
|
+
<promise-iter>.find(<func>, 'result')
|
|
1714
|
+
-> <promise>
|
|
1715
|
+
```
|
|
1716
|
+
|
|
1717
|
+
- `value` (default)
|
|
1718
|
+
resolve to the stored value if found and `undefined` otherwise.
|
|
1719
|
+
- `bool`
|
|
1720
|
+
resolve to `true` if the value is found and `false` otherwise, this is how
|
|
1721
|
+
`.some(..)` is impelemnted.
|
|
1722
|
+
- `result`
|
|
1723
|
+
resolve to the return value of the test `<func>`.
|
|
1724
|
+
|
|
1725
|
+
These are similar to [`<array>.some(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
|
|
1726
|
+
and [`<array>.find(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
|
|
1727
|
+
see them for more info.
|
|
1677
1728
|
|
|
1678
1729
|
#### Array proxy methods returning `<promise-iter>`
|
|
1679
1730
|
|
|
@@ -1697,7 +1748,8 @@ XXX links...
|
|
|
1697
1748
|
|
|
1698
1749
|
- `<promise-iter>.indexOf(..)`
|
|
1699
1750
|
- `<promise-iter>.includes(..)`
|
|
1700
|
-
- `<promise-iter>.every(..)`
|
|
1751
|
+
- `<promise-iter>.every(..)`
|
|
1752
|
+
- `<promise-iter>.findIndex(..)`
|
|
1701
1753
|
|
|
1702
1754
|
These methods are proxies to the appropriate array methods.
|
|
1703
1755
|
|
|
@@ -1727,6 +1779,16 @@ this adds the ability to pass no arguments
|
|
|
1727
1779
|
This will return a generic promise wrapper passing through the results as-is. This
|
|
1728
1780
|
can be useful to hide the extended promise API from further code.
|
|
1729
1781
|
|
|
1782
|
+
#### `promise.IterablePromise.STOP` / `promise.IterablePromise.STOP(..)`
|
|
1783
|
+
|
|
1784
|
+
A special object that when thrown from a function/promise handler will stop
|
|
1785
|
+
further iteration.
|
|
1786
|
+
|
|
1787
|
+
This is `undefined` until the `ig-types/Array` module is loaded.
|
|
1788
|
+
|
|
1789
|
+
For more info see: [Stopping the iteration](#stopping-the-iteration) below, and
|
|
1790
|
+
[the 'Array' STOP section](#arraystop--arraystop)
|
|
1791
|
+
|
|
1730
1792
|
|
|
1731
1793
|
#### Advanced handler
|
|
1732
1794
|
|
|
@@ -1778,6 +1840,24 @@ var p = Promise.iter(
|
|
|
1778
1840
|
console.log(lst) }) // -> [2, 2, 4, 4, [5, 6]]
|
|
1779
1841
|
```
|
|
1780
1842
|
|
|
1843
|
+
#### Stopping the iteration
|
|
1844
|
+
|
|
1845
|
+
Like the [`Array`](#arraystop--arraystop) module, this support throwing `STOP` to
|
|
1846
|
+
stop iteration. As we uses [`.smap(..)`](#arraysmap--arraysfilter--arraysreduce--arraysforeach)
|
|
1847
|
+
stopping support is supported if `ig-types/Array` module is loaded.
|
|
1848
|
+
|
|
1849
|
+
```javascript
|
|
1850
|
+
require('ig-types/Array')
|
|
1851
|
+
```
|
|
1852
|
+
|
|
1853
|
+
This is also different semantically, as promise iteration can happen out of order,
|
|
1854
|
+
stopping affects the order of processing and not order of the input array with one exception: promises already created can not be stopped in `JavaScript`.
|
|
1855
|
+
|
|
1856
|
+
Any handler function passed to a `<promise-iter>` method can `throw` a STOP.
|
|
1857
|
+
|
|
1858
|
+
For more details see: [the 'Array' STOP section](#arraystop--arraystop)
|
|
1859
|
+
|
|
1860
|
+
|
|
1781
1861
|
|
|
1782
1862
|
### Promise proxies
|
|
1783
1863
|
|
|
@@ -1951,7 +2031,7 @@ Chained generators handle items depth-first, i.e. the items are passed as they
|
|
|
1951
2031
|
are yielded down the generator chain.
|
|
1952
2032
|
|
|
1953
2033
|
|
|
1954
|
-
#### `<generator>.iter()`
|
|
2034
|
+
#### `<generator>.iter(..)`
|
|
1955
2035
|
|
|
1956
2036
|
Iterate over the generator.
|
|
1957
2037
|
```bnf
|
|
@@ -1959,7 +2039,24 @@ Iterate over the generator.
|
|
|
1959
2039
|
-> <generator>
|
|
1960
2040
|
```
|
|
1961
2041
|
|
|
1962
|
-
|
|
2042
|
+
XXX move this to `generator.iter(..)`
|
|
2043
|
+
|
|
2044
|
+
Compatible with [`<array>`'s `.iter()`](#arrayiter--arrayiter).
|
|
2045
|
+
|
|
2046
|
+
`.iter(..)` also supports a handler function
|
|
2047
|
+
```bnf
|
|
2048
|
+
<generator>.iter(<handler>)
|
|
2049
|
+
-> <generator>
|
|
2050
|
+
|
|
2051
|
+
|
|
2052
|
+
<handler>(<elem>, <index>)
|
|
2053
|
+
-> <elem>
|
|
2054
|
+
-> [<elem>, ..]
|
|
2055
|
+
-> []
|
|
2056
|
+
```
|
|
2057
|
+
|
|
2058
|
+
Note that the iterables returned by `<handler>(..)` will be expanded, to prevent
|
|
2059
|
+
this wrap them in an array.
|
|
1963
2060
|
|
|
1964
2061
|
|
|
1965
2062
|
#### `<generator>.map(..)` / `<generator>.filter(..)`
|
|
@@ -2084,30 +2181,29 @@ Value added by `.unshift(..)` will be yielded by `<generator>` "first", i.e. on
|
|
|
2084
2181
|
_next_ call to `.next()`, regardless of the current generator state.
|
|
2085
2182
|
|
|
2086
2183
|
|
|
2087
|
-
#### `<generator>.
|
|
2184
|
+
#### `<generator>.then(..)` / `<generator>.catch(..)` / `<generator>.finally(..)`
|
|
2185
|
+
|
|
2186
|
+
Return a promise and resolve it with the generator value.
|
|
2088
2187
|
|
|
2089
2188
|
```bnf
|
|
2090
|
-
<generator>.
|
|
2189
|
+
<generator>.then()
|
|
2091
2190
|
-> <promise>
|
|
2092
2191
|
```
|
|
2093
|
-
Return a promise and resolve it with the generator value.
|
|
2094
2192
|
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
#### `<generator>.then(..)` / `<generator>.catch(..)` / `<generator>.finally(..)`
|
|
2193
|
+
Adding handlers to the promise
|
|
2099
2194
|
|
|
2100
2195
|
```bnf
|
|
2101
2196
|
<generator>.then(<resolve>, <reject>)
|
|
2102
2197
|
-> <promise>
|
|
2103
2198
|
|
|
2104
|
-
<generator>.then(<
|
|
2199
|
+
<generator>.then(<resolve>)
|
|
2105
2200
|
-> <promise>
|
|
2106
2201
|
|
|
2107
2202
|
<generator>.finally(<handler>)
|
|
2108
2203
|
-> <promise>
|
|
2109
2204
|
```
|
|
2110
|
-
|
|
2205
|
+
|
|
2206
|
+
Note that this will deplete the generator.
|
|
2111
2207
|
|
|
2112
2208
|
These are the same as equivalent `Promise` methods, for more info see:
|
|
2113
2209
|
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
|
|
@@ -2411,6 +2507,26 @@ stoppable(<generator>)
|
|
|
2411
2507
|
|
|
2412
2508
|
<!-- XXX example? -->
|
|
2413
2509
|
|
|
2510
|
+
## Async generator extensions
|
|
2511
|
+
|
|
2512
|
+
XXX EXPERIMENTAL
|
|
2513
|
+
|
|
2514
|
+
#### `generator.AsyncGenerator`
|
|
2515
|
+
|
|
2516
|
+
#### `<async-generator>.then(..)` / `<async-generator>.catch(..)` / `<async-generator>.finally(..)`
|
|
2517
|
+
|
|
2518
|
+
#### `<async-generator>.iter(..)`
|
|
2519
|
+
|
|
2520
|
+
#### `<async-generator>.map(..)` / `<async-generator>.filter(..)` / `<async-generator>.reduce(..)`
|
|
2521
|
+
|
|
2522
|
+
#### `<async-generator>.chain(..)`
|
|
2523
|
+
|
|
2524
|
+
#### `<async-generator>.flat(..)`
|
|
2525
|
+
|
|
2526
|
+
#### `<async-generator>.concat(..)`
|
|
2527
|
+
|
|
2528
|
+
#### `<async-generator>.push(..)` / `<async-generator>.unshift(..)`
|
|
2529
|
+
|
|
2414
2530
|
|
|
2415
2531
|
|
|
2416
2532
|
## Containers
|
package/generator.js
CHANGED
|
@@ -66,6 +66,14 @@ module.Generator =
|
|
|
66
66
|
(function*(){}).constructor
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
var AsyncGeneratorPrototype =
|
|
70
|
+
(async function*(){}).constructor.prototype
|
|
71
|
+
|
|
72
|
+
var AsyncGenerator =
|
|
73
|
+
module.AsyncGenerator =
|
|
74
|
+
(async function*(){}).constructor
|
|
75
|
+
|
|
76
|
+
|
|
69
77
|
// base iterator prototypes...
|
|
70
78
|
var ITERATOR_PROTOTYPES = [
|
|
71
79
|
Array,
|
|
@@ -78,13 +86,86 @@ var ITERATOR_PROTOTYPES = [
|
|
|
78
86
|
|
|
79
87
|
//---------------------------------------------------------------------
|
|
80
88
|
|
|
89
|
+
// XXX should this be part of object???
|
|
90
|
+
var stoppable =
|
|
91
|
+
module.stoppable =
|
|
92
|
+
function(func){
|
|
93
|
+
return Object.assign(
|
|
94
|
+
func instanceof Generator ?
|
|
95
|
+
// NOTE: the only difference between Generator/AsyncGenerator
|
|
96
|
+
// versions of this is the async keyword -- keep them
|
|
97
|
+
// in sync...
|
|
98
|
+
function*(){
|
|
99
|
+
try{
|
|
100
|
+
yield* func.call(this, ...arguments)
|
|
101
|
+
} catch(err){
|
|
102
|
+
if(err === STOP){
|
|
103
|
+
return
|
|
104
|
+
} else if(err instanceof STOP){
|
|
105
|
+
yield err.value
|
|
106
|
+
return }
|
|
107
|
+
throw err } }
|
|
108
|
+
: func instanceof AsyncGenerator ?
|
|
109
|
+
// NOTE: the only difference between Generator/AsyncGenerator
|
|
110
|
+
// versions of this is the async keyword -- keep them
|
|
111
|
+
// in sync...
|
|
112
|
+
async function*(){
|
|
113
|
+
try{
|
|
114
|
+
yield* func.call(this, ...arguments)
|
|
115
|
+
} catch(err){
|
|
116
|
+
if(err === STOP){
|
|
117
|
+
return
|
|
118
|
+
} else if(err instanceof STOP){
|
|
119
|
+
yield err.value
|
|
120
|
+
return }
|
|
121
|
+
throw err } }
|
|
122
|
+
: function(){
|
|
123
|
+
try{
|
|
124
|
+
return func.call(this, ...arguments)
|
|
125
|
+
} catch(err){
|
|
126
|
+
if(err === STOP){
|
|
127
|
+
return
|
|
128
|
+
} else if(err instanceof STOP){
|
|
129
|
+
return err.value }
|
|
130
|
+
throw err } },
|
|
131
|
+
{ toString: function(){
|
|
132
|
+
return func.toString() }, }) }
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
//---------------------------------------------------------------------
|
|
81
136
|
// generic generator wrapper...
|
|
137
|
+
|
|
138
|
+
// helper...
|
|
139
|
+
var __iter =
|
|
140
|
+
module.__iter =
|
|
141
|
+
function*(lst=[]){
|
|
142
|
+
if(typeof(lst) == 'object'
|
|
143
|
+
&& Symbol.iterator in lst){
|
|
144
|
+
yield* lst
|
|
145
|
+
} else {
|
|
146
|
+
yield lst } }
|
|
147
|
+
|
|
148
|
+
// XXX updatae Array.js' version for compatibility...
|
|
149
|
+
// XXX DOCS!!!
|
|
82
150
|
var iter =
|
|
83
151
|
module.iter =
|
|
84
152
|
Generator.iter =
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
153
|
+
stoppable(function(lst=[]){
|
|
154
|
+
// handler -> generator-constructor...
|
|
155
|
+
if(typeof(lst) == 'function'){
|
|
156
|
+
// we need to be callable...
|
|
157
|
+
var that = this instanceof Function ?
|
|
158
|
+
this
|
|
159
|
+
// generic root generator...
|
|
160
|
+
: module.__iter
|
|
161
|
+
return function*(){
|
|
162
|
+
yield* that(...arguments).iter(lst) } }
|
|
163
|
+
// no handler -> generator instance...
|
|
164
|
+
return module.__iter(lst) })
|
|
165
|
+
|
|
166
|
+
// NOTE: we need .iter(..) to both return generators if passed an iterable
|
|
167
|
+
// and genereator constructos if passed a function...
|
|
168
|
+
iter.__proto__ = GeneratorPrototype
|
|
88
169
|
|
|
89
170
|
|
|
90
171
|
|
|
@@ -113,9 +194,11 @@ Generator.iter =
|
|
|
113
194
|
|
|
114
195
|
//
|
|
115
196
|
// makeGenerator(<name>)
|
|
197
|
+
// makeGenerator(<name>, <handler>)
|
|
116
198
|
// -> <func>
|
|
117
199
|
//
|
|
118
|
-
// makeGenerator(<name
|
|
200
|
+
// makeGenerator('async', <name>)
|
|
201
|
+
// makeGenerator('async', <name>, <handler>)
|
|
119
202
|
// -> <func>
|
|
120
203
|
//
|
|
121
204
|
//
|
|
@@ -132,14 +215,26 @@ Generator.iter =
|
|
|
132
215
|
// XXX this needs to be of the correct type... (???)
|
|
133
216
|
// XXX need to accept generators as handlers...
|
|
134
217
|
var makeGenerator = function(name, pre){
|
|
218
|
+
var sync = true
|
|
219
|
+
if(name == 'async'){
|
|
220
|
+
sync = false
|
|
221
|
+
var [name, pre] = [...arguments].slice(1) }
|
|
135
222
|
return function(...args){
|
|
136
223
|
var that = this
|
|
137
224
|
return Object.assign(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
225
|
+
// NOTE: the two branches here are identical, the only
|
|
226
|
+
// difference is the async keyword...
|
|
227
|
+
sync ?
|
|
228
|
+
function*(){
|
|
229
|
+
var a = pre ?
|
|
230
|
+
pre.call(this, args, ...arguments)
|
|
231
|
+
: args
|
|
232
|
+
yield* that(...arguments)[name](...a) }
|
|
233
|
+
: async function*(){
|
|
234
|
+
var a = pre ?
|
|
235
|
+
pre.call(this, args, ...arguments)
|
|
236
|
+
: args
|
|
237
|
+
yield* that(...arguments)[name](...a) },
|
|
143
238
|
{ toString: function(){
|
|
144
239
|
return [
|
|
145
240
|
that.toString(),
|
|
@@ -155,34 +250,6 @@ var makePromise = function(name){
|
|
|
155
250
|
return that(...arguments)[name](func) } } }
|
|
156
251
|
|
|
157
252
|
|
|
158
|
-
var stoppable =
|
|
159
|
-
module.stoppable =
|
|
160
|
-
function(func){
|
|
161
|
-
return Object.assign(
|
|
162
|
-
func instanceof Generator ?
|
|
163
|
-
function*(){
|
|
164
|
-
try{
|
|
165
|
-
yield* func.call(this, ...arguments)
|
|
166
|
-
} catch(err){
|
|
167
|
-
if(err === STOP){
|
|
168
|
-
return
|
|
169
|
-
} else if(err instanceof STOP){
|
|
170
|
-
yield err.value
|
|
171
|
-
return }
|
|
172
|
-
throw err } }
|
|
173
|
-
: function(){
|
|
174
|
-
try{
|
|
175
|
-
return func.call(this, ...arguments)
|
|
176
|
-
} catch(err){
|
|
177
|
-
if(err === STOP){
|
|
178
|
-
return
|
|
179
|
-
} else if(err instanceof STOP){
|
|
180
|
-
return err.value }
|
|
181
|
-
throw err } },
|
|
182
|
-
{ toString: function(){
|
|
183
|
-
return func.toString() }, }) }
|
|
184
|
-
|
|
185
|
-
|
|
186
253
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
187
254
|
|
|
188
255
|
var GeneratorMixin =
|
|
@@ -190,9 +257,7 @@ module.GeneratorMixin =
|
|
|
190
257
|
object.Mixin('GeneratorMixin', 'soft', {
|
|
191
258
|
STOP: object.STOP,
|
|
192
259
|
|
|
193
|
-
|
|
194
|
-
iter: function*(lst=[]){
|
|
195
|
-
yield* module.iter(lst) },
|
|
260
|
+
iter: module.iter,
|
|
196
261
|
|
|
197
262
|
gat: makeGenerator('gat'),
|
|
198
263
|
at: function(i){
|
|
@@ -264,15 +329,31 @@ object.Mixin('GeneratorMixin', 'soft', {
|
|
|
264
329
|
e(...args)
|
|
265
330
|
: e }) }),
|
|
266
331
|
//zip: makeGenerator('zip'),
|
|
332
|
+
|
|
333
|
+
enumerate: makeGenerator('enumerate'),
|
|
267
334
|
})
|
|
268
335
|
|
|
269
336
|
|
|
270
337
|
var GeneratorProtoMixin =
|
|
271
338
|
module.GeneratorProtoMixin =
|
|
272
339
|
object.Mixin('GeneratorProtoMixin', 'soft', {
|
|
273
|
-
//
|
|
274
|
-
iter: function*(){
|
|
275
|
-
|
|
340
|
+
// XXX use module.iter(..) ???
|
|
341
|
+
iter: stoppable(function*(handler){
|
|
342
|
+
if(handler){
|
|
343
|
+
var i = 0
|
|
344
|
+
for(var elem of this){
|
|
345
|
+
var res = handler.call(this, elem, i)
|
|
346
|
+
// expand iterables...
|
|
347
|
+
if(typeof(res) == 'object'
|
|
348
|
+
&& Symbol.iterator in res){
|
|
349
|
+
yield* res
|
|
350
|
+
// as-is...
|
|
351
|
+
} else {
|
|
352
|
+
yield res }}
|
|
353
|
+
// no handler...
|
|
354
|
+
} else {
|
|
355
|
+
yield* this } }),
|
|
356
|
+
//*/
|
|
276
357
|
|
|
277
358
|
at: function(i){
|
|
278
359
|
return this.gat(i).next().value },
|
|
@@ -382,17 +463,19 @@ object.Mixin('GeneratorProtoMixin', 'soft', {
|
|
|
382
463
|
|
|
383
464
|
// promises...
|
|
384
465
|
//
|
|
385
|
-
|
|
386
|
-
promise: function(){
|
|
466
|
+
then: function(onresolve, onreject){
|
|
387
467
|
var that = this
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
468
|
+
var p = new Promise(
|
|
469
|
+
function(resolve){
|
|
470
|
+
resolve([...that]) })
|
|
471
|
+
p = (onresolve || onreject) ?
|
|
472
|
+
p.then(...arguments)
|
|
473
|
+
: p
|
|
474
|
+
return p },
|
|
392
475
|
catch: function(func){
|
|
393
|
-
return this.
|
|
476
|
+
return this.then().catch(func) },
|
|
394
477
|
finally: function(func){
|
|
395
|
-
return this.
|
|
478
|
+
return this.then().finally(func) },
|
|
396
479
|
|
|
397
480
|
// combinators...
|
|
398
481
|
//
|
|
@@ -415,6 +498,11 @@ object.Mixin('GeneratorProtoMixin', 'soft', {
|
|
|
415
498
|
// XXX
|
|
416
499
|
},
|
|
417
500
|
//*/
|
|
501
|
+
|
|
502
|
+
enumerate: function*(){
|
|
503
|
+
var i = 0
|
|
504
|
+
for(var e of this){
|
|
505
|
+
yield [i++, e] } },
|
|
418
506
|
})
|
|
419
507
|
|
|
420
508
|
|
|
@@ -428,6 +516,107 @@ ITERATOR_PROTOTYPES
|
|
|
428
516
|
GeneratorProtoMixin(proto) })
|
|
429
517
|
|
|
430
518
|
|
|
519
|
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
520
|
+
// XXX EXPERIMENTAL...
|
|
521
|
+
|
|
522
|
+
var AsyncGeneratorMixin =
|
|
523
|
+
module.AsyncGeneratorMixin =
|
|
524
|
+
object.Mixin('AsyncGeneratorMixin', 'soft', {
|
|
525
|
+
// XXX TEST...
|
|
526
|
+
iter: makeGenerator('async', 'iter'),
|
|
527
|
+
|
|
528
|
+
map: makeGenerator('async', 'map'),
|
|
529
|
+
filter: makeGenerator('async', 'filter'),
|
|
530
|
+
reduce: makeGenerator('async', 'reduce'),
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
var AsyncGeneratorProtoMixin =
|
|
534
|
+
module.AsyncGeneratorProtoMixin =
|
|
535
|
+
object.Mixin('AsyncGeneratorProtoMixin', 'soft', {
|
|
536
|
+
// promise...
|
|
537
|
+
//
|
|
538
|
+
// NOTE: this will unwind the generator...
|
|
539
|
+
// XXX create an iterator promise???
|
|
540
|
+
// XXX should we unwind???
|
|
541
|
+
then: function(resolve, reject){
|
|
542
|
+
var that = this
|
|
543
|
+
var p = new Promise(async function(_resolve, _reject){
|
|
544
|
+
var res = []
|
|
545
|
+
for await(var elem of that){
|
|
546
|
+
res.push(elem) }
|
|
547
|
+
_resolve(res) })
|
|
548
|
+
p = (resolve || reject) ?
|
|
549
|
+
p.then(...arguments)
|
|
550
|
+
: p
|
|
551
|
+
return p },
|
|
552
|
+
catch: function(func){
|
|
553
|
+
return this.then().catch(func) },
|
|
554
|
+
finally: function(){
|
|
555
|
+
return this.then().finally(func) },
|
|
556
|
+
|
|
557
|
+
// XXX might be a good idea to use this approach above...
|
|
558
|
+
iter: stoppable(async function*(handler=undefined){
|
|
559
|
+
var i = 0
|
|
560
|
+
if(handler){
|
|
561
|
+
for await(var e of this){
|
|
562
|
+
var res = handler.call(this, e, i++)
|
|
563
|
+
if(typeof(res) == 'object'
|
|
564
|
+
&& Symbol.iterator in res){
|
|
565
|
+
yield* res
|
|
566
|
+
} else {
|
|
567
|
+
yield res } }
|
|
568
|
+
} else {
|
|
569
|
+
yield* this } }),
|
|
570
|
+
|
|
571
|
+
map: async function*(func){
|
|
572
|
+
yield* this.iter(function(elem, i){
|
|
573
|
+
return [func.call(this, elem, i)] }) },
|
|
574
|
+
filter: async function*(func){
|
|
575
|
+
yield* this.iter(function(elem, i){
|
|
576
|
+
return func.call(this, elem, i) ?
|
|
577
|
+
[elem]
|
|
578
|
+
: [] }) },
|
|
579
|
+
// NOTE: there is not much point in .reduceRight(..) in an async
|
|
580
|
+
// generator as we'll need to fully unwind it then go from the
|
|
581
|
+
// end...
|
|
582
|
+
reduce: async function(func, state){
|
|
583
|
+
this.iter(function(elem, i){
|
|
584
|
+
state = func.call(this, state, elem, i)
|
|
585
|
+
return [] })
|
|
586
|
+
return state },
|
|
587
|
+
|
|
588
|
+
// XXX TEST...
|
|
589
|
+
chain: async function*(...next){
|
|
590
|
+
yield* next
|
|
591
|
+
.reduce(function(cur, next){
|
|
592
|
+
return next(cur) }, this) },
|
|
593
|
+
|
|
594
|
+
flat: async function*(){
|
|
595
|
+
for await(var e of this){
|
|
596
|
+
if(e instanceof Array){
|
|
597
|
+
yield* e
|
|
598
|
+
} else {
|
|
599
|
+
yield e }}},
|
|
600
|
+
|
|
601
|
+
concat: async function*(other){
|
|
602
|
+
yield* this
|
|
603
|
+
yield* other },
|
|
604
|
+
push: async function*(elem){
|
|
605
|
+
yield* this
|
|
606
|
+
yield elem },
|
|
607
|
+
unsift: async function*(elem){
|
|
608
|
+
yield elem
|
|
609
|
+
yield* this },
|
|
610
|
+
|
|
611
|
+
// XXX
|
|
612
|
+
// slice -- not sure if we need this...
|
|
613
|
+
// ...
|
|
614
|
+
})
|
|
615
|
+
|
|
616
|
+
AsyncGeneratorMixin(AsyncGeneratorPrototype)
|
|
617
|
+
AsyncGeneratorProtoMixin(AsyncGeneratorPrototype.prototype)
|
|
618
|
+
|
|
619
|
+
|
|
431
620
|
|
|
432
621
|
//---------------------------------------------------------------------
|
|
433
622
|
// Generators...
|