ig-types 6.13.4 → 6.14.0
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/Promise.js +104 -87
- package/README.md +11 -0
- package/package.json +1 -1
package/Promise.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**********************************************************************
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
2
|
*
|
|
6
3
|
* This defines the following extensions to Promise:
|
|
7
4
|
*
|
|
8
5
|
* Promise.iter(seq)
|
|
6
|
+
* <promise>.iter()
|
|
9
7
|
* Iterable promise object.
|
|
10
8
|
* Similar to Promise.all(..) but adds basic iterator/generator
|
|
11
9
|
* API and will resolve the items as they are ready (resolved).
|
|
@@ -19,6 +17,11 @@
|
|
|
19
17
|
* Exposes the API to resolve/reject the promise object
|
|
20
18
|
* externally.
|
|
21
19
|
*
|
|
20
|
+
* <promise>.as(obj)
|
|
21
|
+
* Promise proxy.
|
|
22
|
+
* Proxies the methods available from obj to promise value.
|
|
23
|
+
*
|
|
24
|
+
*
|
|
22
25
|
*
|
|
23
26
|
*
|
|
24
27
|
**********************************************/ /* c8 ignore next 2 */
|
|
@@ -28,18 +31,6 @@
|
|
|
28
31
|
|
|
29
32
|
var object = require('ig-object')
|
|
30
33
|
|
|
31
|
-
// XXX required for STOP...
|
|
32
|
-
//var generator = require('./generator')
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
/*********************************************************************/
|
|
36
|
-
|
|
37
|
-
/* XXX not used yet...
|
|
38
|
-
// NOTE: this is used in a similar fashion to Python's StopIteration...
|
|
39
|
-
var STOP =
|
|
40
|
-
module.STOP =
|
|
41
|
-
object.STOP
|
|
42
|
-
//*/
|
|
43
34
|
|
|
44
35
|
|
|
45
36
|
//---------------------------------------------------------------------
|
|
@@ -48,13 +39,38 @@ module.STOP =
|
|
|
48
39
|
// Like Promise.all(..) but adds ability to iterate through results
|
|
49
40
|
// via generators .map(..)/.reduce(..) and friends...
|
|
50
41
|
//
|
|
42
|
+
// NOTE: it would be nice to support throwing STOP 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
|
+
//
|
|
53
|
+
|
|
54
|
+
// NOTE: we are not using async/await here as we need to control the
|
|
55
|
+
// type of promise returned in cases where we know we are returning
|
|
56
|
+
// an array...
|
|
57
|
+
// XXX should these be exported???
|
|
58
|
+
var iterPromiseProxy =
|
|
59
|
+
//module.iterPromiseProxy =
|
|
60
|
+
function(name){
|
|
61
|
+
return function(...args){
|
|
62
|
+
return this.constructor(
|
|
63
|
+
this.then(function(lst){
|
|
64
|
+
return lst[name](...args) })) } }
|
|
65
|
+
var promiseProxy =
|
|
66
|
+
//module.promiseProxy =
|
|
67
|
+
function(name){
|
|
68
|
+
return async function(...args){
|
|
69
|
+
return (await this)[name](...args) } }
|
|
51
70
|
|
|
52
71
|
var IterablePromise =
|
|
53
72
|
module.IterablePromise =
|
|
54
73
|
object.Constructor('IterablePromise', Promise, {
|
|
55
|
-
// XXX
|
|
56
|
-
//STOP: object.STOP,
|
|
57
|
-
|
|
58
74
|
//
|
|
59
75
|
// Format:
|
|
60
76
|
// [
|
|
@@ -64,6 +80,13 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
64
80
|
// ...
|
|
65
81
|
// ]
|
|
66
82
|
//
|
|
83
|
+
// This format has several useful features:
|
|
84
|
+
// - concatenating packed list results in a packed list
|
|
85
|
+
// - adding an iterable promise (as-is) into a packed list results
|
|
86
|
+
// in a packed list
|
|
87
|
+
//
|
|
88
|
+
// NOTE: in general iterable promises are implicitly immutable, so
|
|
89
|
+
// it is not recomended to ever edit this inplace...
|
|
67
90
|
__list: null,
|
|
68
91
|
|
|
69
92
|
// low-level .__list handlers/helpers...
|
|
@@ -163,8 +186,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
163
186
|
// .includes(..)
|
|
164
187
|
// .some(..) / .every(..)
|
|
165
188
|
// .sort(..)
|
|
166
|
-
//
|
|
167
|
-
// XXX should these support STOP???
|
|
189
|
+
// XXX update this note...
|
|
168
190
|
map: function(func){
|
|
169
191
|
return this.constructor(this,
|
|
170
192
|
function(e){
|
|
@@ -188,11 +210,9 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
188
210
|
// what the user reduces to...
|
|
189
211
|
// XXX we could look at the initial state though...
|
|
190
212
|
// NOTE: the items can be handled out of order because the nested
|
|
191
|
-
// promises can resolve in any order
|
|
192
|
-
// XXX doc how to go around this...
|
|
213
|
+
// promises can resolve in any order...
|
|
193
214
|
// NOTE: since order of execution can not be guaranteed there is no
|
|
194
215
|
// point in implementing .reduceRight(..)
|
|
195
|
-
// XXX should func be able to return a promise???
|
|
196
216
|
reduce: function(func, res){
|
|
197
217
|
return this.constructor(this,
|
|
198
218
|
function(e){
|
|
@@ -200,14 +220,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
200
220
|
return [] })
|
|
201
221
|
.then(function(){
|
|
202
222
|
return res }) },
|
|
203
|
-
|
|
204
|
-
// adding this.
|
|
205
|
-
reduceRight: function(func, res){
|
|
206
|
-
return this
|
|
207
|
-
.reverse()
|
|
208
|
-
.reduce(...arguments)
|
|
209
|
-
.reverse() },
|
|
210
|
-
//*/
|
|
223
|
+
|
|
211
224
|
flat: function(depth=1){
|
|
212
225
|
return this.constructor(this,
|
|
213
226
|
function(e){
|
|
@@ -246,21 +259,17 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
246
259
|
var cur = this.__pack(this)
|
|
247
260
|
var other = this.__pack(other)
|
|
248
261
|
return this.constructor(
|
|
249
|
-
// NOTE: we
|
|
250
|
-
//
|
|
251
|
-
//
|
|
262
|
+
// NOTE: we need to keep things as exposed as possible, this
|
|
263
|
+
// is why we're not blanketing all the cases with
|
|
264
|
+
// Promise.all(..)...
|
|
252
265
|
(cur instanceof Promise
|
|
253
266
|
&& other instanceof Promise) ?
|
|
254
|
-
|
|
255
|
-
.then(function(list){
|
|
256
|
-
return list[0].concat(list[1]) })
|
|
267
|
+
[cur, other]
|
|
257
268
|
: cur instanceof Promise ?
|
|
258
|
-
cur
|
|
259
|
-
return list.concat(other) })
|
|
269
|
+
[cur, ...other]
|
|
260
270
|
: other instanceof Promise ?
|
|
261
|
-
other
|
|
262
|
-
|
|
263
|
-
: cur.concat(other),
|
|
271
|
+
[...cur, other]
|
|
272
|
+
: [...cur, ...other],
|
|
264
273
|
'raw') },
|
|
265
274
|
push: function(elem){
|
|
266
275
|
return this.concat([elem]) },
|
|
@@ -268,14 +277,54 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
268
277
|
return this.constructor([elem])
|
|
269
278
|
.concat(this) },
|
|
270
279
|
|
|
271
|
-
// XXX
|
|
280
|
+
// XXX can we do these?
|
|
272
281
|
// .pop()
|
|
273
282
|
// .shift()
|
|
274
|
-
// .
|
|
275
|
-
// .at(..)
|
|
283
|
+
// .splice(..)
|
|
276
284
|
// ...would be nice if these could stop everything that's not
|
|
277
|
-
// needed to execute
|
|
285
|
+
// needed to execute -- likely not possible (XXX)
|
|
286
|
+
// ...these need to somehow both return an element and affect
|
|
287
|
+
// the iterator (or return a new one) -- we can trivially do either
|
|
288
|
+
// one action within the spec but not both...
|
|
289
|
+
|
|
290
|
+
// NOTE: this can avoid waiting for the whole promise to resolve only
|
|
291
|
+
// for indexes 0 and -1, everything else is non-deterministic and
|
|
292
|
+
// we'll have to wait for the whole thing to resolve.
|
|
293
|
+
at: async function(i){
|
|
294
|
+
var list = this.__list
|
|
295
|
+
return ((i != 0 && i != -1)
|
|
296
|
+
|| list instanceof Promise
|
|
297
|
+
|| list.at(i) instanceof Promise) ?
|
|
298
|
+
(await this).at(i)
|
|
299
|
+
// NOTE: we can only reason about first/last explicit elements,
|
|
300
|
+
// anything else is non-deterministic...
|
|
301
|
+
: list.at(i) instanceof Promise ?
|
|
302
|
+
[await list.at(i)].flat().at(i)
|
|
303
|
+
: list.at(i) instanceof Array ?
|
|
304
|
+
list.at(i).at(i)
|
|
305
|
+
: list.at(i) },
|
|
306
|
+
first: function(){
|
|
307
|
+
return this.at(0) },
|
|
308
|
+
last: function(){
|
|
309
|
+
return this.at(-1) },
|
|
278
310
|
|
|
311
|
+
// NOTE: there is no way we can do a sync generator returning
|
|
312
|
+
// promises for values because any promise in .__list makes the
|
|
313
|
+
// value count/index non-deterministic...
|
|
314
|
+
sort: iterPromiseProxy('sort'),
|
|
315
|
+
slice: iterPromiseProxy('slice'),
|
|
316
|
+
entries: iterPromiseProxy('entries'),
|
|
317
|
+
keys: iterPromiseProxy('keys'),
|
|
318
|
+
// XXX we could possibly make this better via .map(..)
|
|
319
|
+
values: iterPromiseProxy('values'),
|
|
320
|
+
|
|
321
|
+
indexOf: promiseProxy('indexOf'),
|
|
322
|
+
includes: promiseProxy('includes'),
|
|
323
|
+
|
|
324
|
+
every: promiseProxy('every'),
|
|
325
|
+
// XXX this can be lazy...
|
|
326
|
+
some: promiseProxy('some'),
|
|
327
|
+
|
|
279
328
|
|
|
280
329
|
// Overload .then(..), .catch(..) and .finally(..) to return a plain
|
|
281
330
|
// Promise instnace...
|
|
@@ -311,18 +360,19 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
311
360
|
//
|
|
312
361
|
//
|
|
313
362
|
// handler(e)
|
|
314
|
-
// -> [value]
|
|
363
|
+
// -> [value, ..]
|
|
315
364
|
// -> []
|
|
365
|
+
// -> <promise>
|
|
316
366
|
//
|
|
317
367
|
//
|
|
318
|
-
// NOTE: element index is unknowable
|
|
368
|
+
// NOTE: element index is unknowable until the full list is expanded
|
|
319
369
|
// as handler(..)'s return value can expand to any number of
|
|
320
370
|
// items...
|
|
321
371
|
// XXX we can make the index a promise, then if the client needs
|
|
322
372
|
// the value they can wait for it...
|
|
323
373
|
//
|
|
324
374
|
//
|
|
325
|
-
//
|
|
375
|
+
// Special cases useful for extending this constructor...
|
|
326
376
|
//
|
|
327
377
|
// Set raw .__list without any pre-processing...
|
|
328
378
|
// Promise.iter([ .. ], 'raw')
|
|
@@ -333,45 +383,18 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
333
383
|
// -> iterable-promise
|
|
334
384
|
//
|
|
335
385
|
//
|
|
336
|
-
// XXX if list is an iterator, can we fill this async???
|
|
337
386
|
// XXX iterator/generator as input:
|
|
338
387
|
// - do we unwind here or externally?
|
|
339
388
|
// ...feels like with the generator external unwinding is
|
|
340
389
|
// needed...
|
|
341
|
-
// XXX
|
|
342
|
-
// - this is more complicated than simply suing .smap(..) instead
|
|
343
|
-
// of .map(..) because the list can contain async promises...
|
|
344
|
-
// ...would need to wrap each .then(..) call in try-catch and
|
|
345
|
-
// manually handle the stop...
|
|
346
|
-
// - another issue here is that the stop would happen in order of
|
|
347
|
-
// execution and not order of elements...
|
|
348
|
-
// XXX DOC:
|
|
349
|
-
// inputs:
|
|
350
|
-
// - Chaining -- list instanceof IterablePromise
|
|
351
|
-
// After all the promises resolve .flat() should
|
|
352
|
-
// turn this into the input list.
|
|
353
|
-
// For this to work we'll need to at least wrap all
|
|
354
|
-
// arrays and promise results in arrays.
|
|
355
|
-
// (currently each value is wrapped)
|
|
356
|
-
// -> __list
|
|
357
|
-
// - promise (value | array)
|
|
358
|
-
// - array of:
|
|
359
|
-
// - array
|
|
360
|
-
// - value
|
|
361
|
-
// - promise (value | array)
|
|
362
|
-
// - New
|
|
363
|
-
// - promise (value | array)
|
|
364
|
-
// - value (non-array)
|
|
365
|
-
// - array of:
|
|
366
|
-
// - value
|
|
367
|
-
// - promise (value)
|
|
390
|
+
// XXX how do we handle errors/rejections???
|
|
368
391
|
__new__: function(_, list, handler){
|
|
369
392
|
// instance...
|
|
370
393
|
var promise
|
|
371
394
|
var obj = Reflect.construct(
|
|
372
395
|
IterablePromise.__proto__,
|
|
373
396
|
[function(resolve, reject){
|
|
374
|
-
// NOTE: this is here for Promise
|
|
397
|
+
// NOTE: this is here for Promise compatibility...
|
|
375
398
|
if(typeof(list) == 'function'){
|
|
376
399
|
return list.call(this, ...arguments) }
|
|
377
400
|
// initial reject...
|
|
@@ -380,17 +403,17 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
380
403
|
promise = {resolve, reject} }],
|
|
381
404
|
IterablePromise)
|
|
382
405
|
|
|
406
|
+
// populate new instance...
|
|
383
407
|
if(promise){
|
|
408
|
+
// handle/pack input data...
|
|
384
409
|
if(handler != 'raw'){
|
|
385
410
|
list = list instanceof IterablePromise ?
|
|
386
411
|
this.__handle(list.__list, handler)
|
|
387
412
|
: this.__pack(list, handler) }
|
|
388
|
-
|
|
389
413
|
Object.defineProperty(obj, '__list', {
|
|
390
414
|
value: list,
|
|
391
415
|
enumerable: false,
|
|
392
416
|
})
|
|
393
|
-
|
|
394
417
|
// handle promise state...
|
|
395
418
|
this.__unpack(list)
|
|
396
419
|
.then(function(list){
|
|
@@ -572,10 +595,7 @@ object.Constructor('ProxyPromise', Promise, {
|
|
|
572
595
|
&& !value.enumerable){
|
|
573
596
|
return }
|
|
574
597
|
// proxy...
|
|
575
|
-
obj[key] =
|
|
576
|
-
// XXX should we also .catch(..) here???
|
|
577
|
-
return context.then(function(res){
|
|
578
|
-
return res[key](...args) }) } })
|
|
598
|
+
obj[key] = promiseProxy(key) })
|
|
579
599
|
proto = proto.__proto__ }
|
|
580
600
|
return obj },
|
|
581
601
|
})
|
|
@@ -595,13 +615,10 @@ object.Mixin('PromiseMixin', 'soft', {
|
|
|
595
615
|
PromiseMixin(Promise)
|
|
596
616
|
|
|
597
617
|
|
|
598
|
-
// XXX EXPEREMENTAL...
|
|
599
618
|
var PromiseProtoMixin =
|
|
600
619
|
module.PromiseProtoMixin =
|
|
601
620
|
object.Mixin('PromiseProtoMixin', 'soft', {
|
|
602
621
|
as: ProxyPromise,
|
|
603
|
-
|
|
604
|
-
// XXX
|
|
605
622
|
iter: function(handler){
|
|
606
623
|
return IterablePromise(this, handler) },
|
|
607
624
|
})
|
package/README.md
CHANGED
|
@@ -1508,6 +1508,17 @@ promise, even if the original is resolved.
|
|
|
1508
1508
|
If all values are resolved the `<promise-iter>` will resolve on the next
|
|
1509
1509
|
execution frame.
|
|
1510
1510
|
|
|
1511
|
+
There are two types of iterator methods here, both are transparent but different
|
|
1512
|
+
in how they process values:
|
|
1513
|
+
- *Parallel methods*
|
|
1514
|
+
These handle elements as soon as they are available even if the parent promise
|
|
1515
|
+
is not yet resolved.
|
|
1516
|
+
<!-- XXX list -->
|
|
1517
|
+
- *Proxies*
|
|
1518
|
+
These methods simply wait for the main promise to resolve and then call the
|
|
1519
|
+
appropriate method on the result.
|
|
1520
|
+
<!-- XXX list + mark definitions as "(proxy)" -->
|
|
1521
|
+
|
|
1511
1522
|
<!--
|
|
1512
1523
|
XXX should we support generators as input?
|
|
1513
1524
|
...not sure about the control flow direction here, on one hand the generator
|