ig-types 6.14.0 → 6.14.1
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 +112 -80
- package/README.md +51 -0
- package/package.json +1 -1
package/Promise.js
CHANGED
|
@@ -39,7 +39,7 @@ var object = require('ig-object')
|
|
|
39
39
|
// Like Promise.all(..) but adds ability to iterate through results
|
|
40
40
|
// via generators .map(..)/.reduce(..) and friends...
|
|
41
41
|
//
|
|
42
|
-
// NOTE: it would be nice to support throwing STOP from the iterable
|
|
42
|
+
// NOTE: it would be nice to support throwing STOP (XXX) from the iterable
|
|
43
43
|
// promise but...
|
|
44
44
|
// - this is more complicated than simply using .smap(..) instead
|
|
45
45
|
// of .map(..) because the list can contain async promises...
|
|
@@ -49,11 +49,27 @@ var object = require('ig-object')
|
|
|
49
49
|
// - another issue here is that the stop would happen in order of
|
|
50
50
|
// execution and not order of elements...
|
|
51
51
|
// XXX though stopping within a single level might be useful...
|
|
52
|
-
//
|
|
53
|
-
|
|
52
|
+
// NOTE: the following can not be implemented here:
|
|
53
|
+
// .splice(..) - can't both modify and return
|
|
54
|
+
// a result...
|
|
55
|
+
// .pop() / .shift() - can't modify the promise, use
|
|
56
|
+
// .first() / .last() instead.
|
|
57
|
+
// [Symbol.iterator]() - needs to be sync and we can't
|
|
58
|
+
// know the number of elements to
|
|
59
|
+
// return promises before the whole
|
|
60
|
+
// iterable promise is resolved.
|
|
54
61
|
// NOTE: we are not using async/await here as we need to control the
|
|
55
62
|
// type of promise returned in cases where we know we are returning
|
|
56
63
|
// an array...
|
|
64
|
+
// NOTE: there is no point in implementing a 1:1 version of this that
|
|
65
|
+
// would not support element expansion/contraction as it would only
|
|
66
|
+
// simplify a couple of methods that are 1:1 (like .map(..) and
|
|
67
|
+
// .some(..)) while methods like .filter(..) will throw everything
|
|
68
|
+
// back to the complex IterablePromise...
|
|
69
|
+
//
|
|
70
|
+
// XXX how do we handle errors/rejections???
|
|
71
|
+
//
|
|
72
|
+
|
|
57
73
|
// XXX should these be exported???
|
|
58
74
|
var iterPromiseProxy =
|
|
59
75
|
//module.iterPromiseProxy =
|
|
@@ -71,6 +87,9 @@ function(name){
|
|
|
71
87
|
var IterablePromise =
|
|
72
88
|
module.IterablePromise =
|
|
73
89
|
object.Constructor('IterablePromise', Promise, {
|
|
90
|
+
// packed array...
|
|
91
|
+
//
|
|
92
|
+
// Holds promise state.
|
|
74
93
|
//
|
|
75
94
|
// Format:
|
|
76
95
|
// [
|
|
@@ -87,16 +106,20 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
87
106
|
//
|
|
88
107
|
// NOTE: in general iterable promises are implicitly immutable, so
|
|
89
108
|
// it is not recomended to ever edit this inplace...
|
|
90
|
-
|
|
109
|
+
// NOTE: we are not isolation any internals to enable users to
|
|
110
|
+
// responsibly extend the code.
|
|
111
|
+
__packed: null,
|
|
91
112
|
|
|
92
|
-
// low-level .
|
|
113
|
+
// low-level .__packed handlers/helpers...
|
|
93
114
|
//
|
|
94
115
|
// NOTE: these can be useful for debugging and extending...
|
|
95
|
-
|
|
116
|
+
//
|
|
117
|
+
// pack and oprionally transform/handle an array (sync)...
|
|
118
|
+
__pack: function(list, handler=undefined){
|
|
96
119
|
var that = this
|
|
97
120
|
// handle iterable promise list...
|
|
98
121
|
if(list instanceof IterablePromise){
|
|
99
|
-
return this.__handle(list.
|
|
122
|
+
return this.__handle(list.__packed, handler) }
|
|
100
123
|
// handle promise list...
|
|
101
124
|
if(list instanceof Promise){
|
|
102
125
|
return list.then(function(list){
|
|
@@ -120,11 +143,12 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
120
143
|
: !handle ?
|
|
121
144
|
elem
|
|
122
145
|
: handler(elem) }) },
|
|
123
|
-
|
|
146
|
+
// transform/handle packed array (sync)...
|
|
147
|
+
__handle: function(list, handler=undefined){
|
|
124
148
|
var that = this
|
|
125
149
|
if(typeof(list) == 'function'){
|
|
126
150
|
handler = list
|
|
127
|
-
list = this.
|
|
151
|
+
list = this.__packed }
|
|
128
152
|
if(!handler){
|
|
129
153
|
return list }
|
|
130
154
|
// handle promise list...
|
|
@@ -144,49 +168,28 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
144
168
|
return elem.flat() })
|
|
145
169
|
: [handler(elem)] })
|
|
146
170
|
.flat() },
|
|
147
|
-
|
|
171
|
+
// unpack array (async)...
|
|
172
|
+
__unpack: async function(list){
|
|
148
173
|
list = list
|
|
149
|
-
?? this.
|
|
174
|
+
?? this.__packed
|
|
150
175
|
// handle promise list...
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return Promise.all(list)
|
|
157
|
-
.then(function(list){
|
|
158
|
-
return list.flat() }) },
|
|
176
|
+
return list instanceof Promise ?
|
|
177
|
+
this.__unpack(await list)
|
|
178
|
+
// do the work...
|
|
179
|
+
: (await Promise.all(list))
|
|
180
|
+
.flat() },
|
|
159
181
|
|
|
160
182
|
|
|
161
183
|
// iterator methods...
|
|
162
184
|
//
|
|
163
185
|
// These will return a new IterablePromise instance...
|
|
164
186
|
//
|
|
165
|
-
// When called from a resolved promise these will return a new
|
|
166
|
-
// resolved promise with updated values...
|
|
167
|
-
//
|
|
168
|
-
// When called from a rejected promise these will return a rejected
|
|
169
|
-
// with the same reason promise...
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
187
|
// NOTE: these are different to Array's equivalents in that the handler
|
|
173
188
|
// is called not in the order of the elements but rather in order
|
|
174
189
|
// of promise resolution...
|
|
175
190
|
// NOTE: index of items is unknowable because items can expand and
|
|
176
|
-
// contract depending on
|
|
191
|
+
// contract depending on handlers (e.g. .filter(..) can remove
|
|
177
192
|
// items)...
|
|
178
|
-
// This the following can not be implemented here:
|
|
179
|
-
// .slice(..)
|
|
180
|
-
// .splice(..)
|
|
181
|
-
// .values() / .keys()
|
|
182
|
-
// .at(..)
|
|
183
|
-
// [Symbol.iterator]() - needs to be sync...
|
|
184
|
-
// The followng methods are questionable:
|
|
185
|
-
// .indexOf(..)
|
|
186
|
-
// .includes(..)
|
|
187
|
-
// .some(..) / .every(..)
|
|
188
|
-
// .sort(..)
|
|
189
|
-
// XXX update this note...
|
|
190
193
|
map: function(func){
|
|
191
194
|
return this.constructor(this,
|
|
192
195
|
function(e){
|
|
@@ -208,11 +211,11 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
208
211
|
: _filter(e) }) },
|
|
209
212
|
// NOTE: this does not return an iterable promise as we can't know
|
|
210
213
|
// what the user reduces to...
|
|
211
|
-
// XXX we could look at the initial state though...
|
|
212
214
|
// NOTE: the items can be handled out of order because the nested
|
|
213
215
|
// promises can resolve in any order...
|
|
214
216
|
// NOTE: since order of execution can not be guaranteed there is no
|
|
215
|
-
// point in implementing .reduceRight(..)
|
|
217
|
+
// point in implementing .reduceRight(..) in the same way
|
|
218
|
+
// (see below)...
|
|
216
219
|
reduce: function(func, res){
|
|
217
220
|
return this.constructor(this,
|
|
218
221
|
function(e){
|
|
@@ -232,7 +235,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
232
235
|
e
|
|
233
236
|
: [e] }) },
|
|
234
237
|
reverse: function(){
|
|
235
|
-
var lst = this.
|
|
238
|
+
var lst = this.__packed
|
|
236
239
|
return this.constructor(
|
|
237
240
|
lst instanceof Promise ?
|
|
238
241
|
lst.then(function(elems){
|
|
@@ -277,21 +280,24 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
277
280
|
return this.constructor([elem])
|
|
278
281
|
.concat(this) },
|
|
279
282
|
|
|
280
|
-
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
//
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
|
|
290
|
-
//
|
|
291
|
-
//
|
|
292
|
-
//
|
|
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
|
+
// proxy methods...
|
|
290
|
+
//
|
|
291
|
+
// These require the whole promise to resolve to trigger.
|
|
292
|
+
//
|
|
293
|
+
// An exception to this would be .at(0)/.first() and .at(-1)/.last()
|
|
294
|
+
// that can get the target element if it's accessible.
|
|
295
|
+
//
|
|
296
|
+
// NOTE: methods that are guaranteed to return an array will return
|
|
297
|
+
// an iterable promise (created with iterPromiseProxy(..))...
|
|
298
|
+
//
|
|
293
299
|
at: async function(i){
|
|
294
|
-
var list = this.
|
|
300
|
+
var list = this.__packed
|
|
295
301
|
return ((i != 0 && i != -1)
|
|
296
302
|
|| list instanceof Promise
|
|
297
303
|
|| list.at(i) instanceof Promise) ?
|
|
@@ -308,24 +314,35 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
308
314
|
last: function(){
|
|
309
315
|
return this.at(-1) },
|
|
310
316
|
|
|
317
|
+
// NOTE: unlike .reduce(..) this needs the parent fully resolved
|
|
318
|
+
// to be able to iterate from the end.
|
|
319
|
+
// XXX ???
|
|
320
|
+
reduceRight: promiseProxy('reduceRight'),
|
|
321
|
+
|
|
311
322
|
// NOTE: there is no way we can do a sync generator returning
|
|
312
|
-
// promises for values because any promise in .
|
|
323
|
+
// promises for values because any promise in .__packed makes the
|
|
313
324
|
// value count/index non-deterministic...
|
|
314
325
|
sort: iterPromiseProxy('sort'),
|
|
326
|
+
// XXX we could have a special-case here for .slice()/slice(0, -1)
|
|
327
|
+
// and possibly othets, should we???
|
|
315
328
|
slice: iterPromiseProxy('slice'),
|
|
329
|
+
|
|
316
330
|
entries: iterPromiseProxy('entries'),
|
|
317
331
|
keys: iterPromiseProxy('keys'),
|
|
318
332
|
// XXX we could possibly make this better via .map(..)
|
|
319
333
|
values: iterPromiseProxy('values'),
|
|
320
334
|
|
|
321
335
|
indexOf: promiseProxy('indexOf'),
|
|
336
|
+
lastIndexOf: promiseProxy('lastIndexOf'),
|
|
322
337
|
includes: promiseProxy('includes'),
|
|
323
338
|
|
|
324
339
|
every: promiseProxy('every'),
|
|
325
|
-
// XXX this can be lazy...
|
|
340
|
+
// XXX this can be lazy... (???)
|
|
326
341
|
some: promiseProxy('some'),
|
|
327
342
|
|
|
328
343
|
|
|
344
|
+
// promise api...
|
|
345
|
+
//
|
|
329
346
|
// Overload .then(..), .catch(..) and .finally(..) to return a plain
|
|
330
347
|
// Promise instnace...
|
|
331
348
|
//
|
|
@@ -351,6 +368,13 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
351
368
|
: p },
|
|
352
369
|
|
|
353
370
|
|
|
371
|
+
// this is defined globally as Promise.prototype.iter(.,)
|
|
372
|
+
//
|
|
373
|
+
// for details see: PromiseMixin(..) below...
|
|
374
|
+
//iter: function(handler=undefined){ ... },
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
// constructor...
|
|
354
378
|
//
|
|
355
379
|
// Promise.iter([ .. ])
|
|
356
380
|
// -> iterable-promise
|
|
@@ -374,7 +398,7 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
374
398
|
//
|
|
375
399
|
// Special cases useful for extending this constructor...
|
|
376
400
|
//
|
|
377
|
-
// Set raw .
|
|
401
|
+
// Set raw .__packed without any pre-processing...
|
|
378
402
|
// Promise.iter([ .. ], 'raw')
|
|
379
403
|
// -> iterable-promise
|
|
380
404
|
//
|
|
@@ -382,12 +406,6 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
382
406
|
// Promise.iter(false)
|
|
383
407
|
// -> iterable-promise
|
|
384
408
|
//
|
|
385
|
-
//
|
|
386
|
-
// XXX iterator/generator as input:
|
|
387
|
-
// - do we unwind here or externally?
|
|
388
|
-
// ...feels like with the generator external unwinding is
|
|
389
|
-
// needed...
|
|
390
|
-
// XXX how do we handle errors/rejections???
|
|
391
409
|
__new__: function(_, list, handler){
|
|
392
410
|
// instance...
|
|
393
411
|
var promise
|
|
@@ -408,9 +426,9 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
408
426
|
// handle/pack input data...
|
|
409
427
|
if(handler != 'raw'){
|
|
410
428
|
list = list instanceof IterablePromise ?
|
|
411
|
-
this.__handle(list.
|
|
429
|
+
this.__handle(list.__packed, handler)
|
|
412
430
|
: this.__pack(list, handler) }
|
|
413
|
-
Object.defineProperty(obj, '
|
|
431
|
+
Object.defineProperty(obj, '__packed', {
|
|
414
432
|
value: list,
|
|
415
433
|
enumerable: false,
|
|
416
434
|
})
|
|
@@ -473,13 +491,14 @@ object.Constructor('InteractivePromise', Promise, {
|
|
|
473
491
|
// register a handler...
|
|
474
492
|
} else {
|
|
475
493
|
var h = obj == null ?
|
|
476
|
-
// NOTE: we need to get the handlers from
|
|
477
|
-
// unless we are not
|
|
478
|
-
// bootstrap
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
//
|
|
494
|
+
// NOTE: we need to get the handlers from
|
|
495
|
+
// .__message_handlers unless we are not
|
|
496
|
+
// fully defined yet, then use the bootstrap
|
|
497
|
+
// container (handlers)...
|
|
498
|
+
// ...since we can call onmessage(..) while
|
|
499
|
+
// the promise is still defined there is no
|
|
500
|
+
// way to .send(..) until it returns a promise
|
|
501
|
+
// object, this races here are highly unlikely...
|
|
483
502
|
handlers
|
|
484
503
|
: (obj.__message_handlers =
|
|
485
504
|
obj.__message_handlers ?? [])
|
|
@@ -566,10 +585,13 @@ object.Constructor('CooperativePromise', Promise, {
|
|
|
566
585
|
var ProxyPromise =
|
|
567
586
|
module.ProxyPromise =
|
|
568
587
|
object.Constructor('ProxyPromise', Promise, {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
588
|
+
|
|
589
|
+
then: IterablePromise.prototype.then,
|
|
590
|
+
|
|
591
|
+
__new__: function(context, other, nooverride=false){
|
|
592
|
+
var proto = 'prototype' in other ?
|
|
593
|
+
other.prototype
|
|
594
|
+
: other
|
|
573
595
|
var obj = Reflect.construct(
|
|
574
596
|
ProxyPromise.__proto__,
|
|
575
597
|
[function(resolve, reject){
|
|
@@ -580,6 +602,9 @@ object.Constructor('ProxyPromise', Promise, {
|
|
|
580
602
|
// NOTE: we are not using object.deepKeys(..) here as we need
|
|
581
603
|
// the key origin not to trigger property getters...
|
|
582
604
|
var seen = new Set()
|
|
605
|
+
nooverride = nooverride instanceof Array ?
|
|
606
|
+
new Set(nooverride)
|
|
607
|
+
: nooverride
|
|
583
608
|
while(proto != null){
|
|
584
609
|
Object.entries(Object.getOwnPropertyDescriptors(proto))
|
|
585
610
|
.forEach(function([key, value]){
|
|
@@ -594,6 +619,13 @@ object.Constructor('ProxyPromise', Promise, {
|
|
|
594
619
|
&& Object.prototype.run === value.value)
|
|
595
620
|
&& !value.enumerable){
|
|
596
621
|
return }
|
|
622
|
+
// do not override existing methods...
|
|
623
|
+
if(nooverride === true ?
|
|
624
|
+
key in obj
|
|
625
|
+
: nooverride instanceof Set ?
|
|
626
|
+
nooverride.has(key)
|
|
627
|
+
: nooverride){
|
|
628
|
+
return }
|
|
597
629
|
// proxy...
|
|
598
630
|
obj[key] = promiseProxy(key) })
|
|
599
631
|
proto = proto.__proto__ }
|
|
@@ -619,7 +651,7 @@ var PromiseProtoMixin =
|
|
|
619
651
|
module.PromiseProtoMixin =
|
|
620
652
|
object.Mixin('PromiseProtoMixin', 'soft', {
|
|
621
653
|
as: ProxyPromise,
|
|
622
|
-
iter: function(handler){
|
|
654
|
+
iter: function(handler=undefined){
|
|
623
655
|
return IterablePromise(this, handler) },
|
|
624
656
|
})
|
|
625
657
|
|
|
@@ -629,4 +661,4 @@ PromiseProtoMixin(Promise.prototype)
|
|
|
629
661
|
|
|
630
662
|
|
|
631
663
|
/**********************************************************************
|
|
632
|
-
* vim:set ts=4 sw=4 :
|
|
664
|
+
* vim:set ts=4 sw=4 nowrap : */ return module })
|
package/README.md
CHANGED
|
@@ -77,6 +77,9 @@ Library of JavaScript type extensions, types and utilities.
|
|
|
77
77
|
- [`<promise-iter>.reverse()`](#promise-iterreverse)
|
|
78
78
|
- [`<promise-iter>.concat(..)`](#promise-iterconcat)
|
|
79
79
|
- [`<promise-iter>.push(..)` / `<promise-iter>.unshift(..)`](#promise-iterpush--promise-iterunshift)
|
|
80
|
+
- [`<promise-iter>.at(..)` / `<promise-iter>.first()` / `<promise-iter>.last()`](#promise-iterat--promise-iterfirst--promise-iterlast)
|
|
81
|
+
- [Array proxy methods returning `<promise-iter>`](#array-proxy-methods-returning-promise-iter)
|
|
82
|
+
- [Array proxy methods returning a `<promise>`](#array-proxy-methods-returning-a-promise)
|
|
80
83
|
- [`<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally)
|
|
81
84
|
- [Advanced handler](#advanced-handler)
|
|
82
85
|
- [Promise proxies](#promise-proxies)
|
|
@@ -1663,6 +1666,54 @@ and [`<array>.unshift(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScr
|
|
|
1663
1666
|
see them for more info.
|
|
1664
1667
|
|
|
1665
1668
|
|
|
1669
|
+
#### `<promise-iter>.at(..)` / `<promise-iter>.first()` / `<promise-iter>.last()`
|
|
1670
|
+
|
|
1671
|
+
Proxies to the appropriate array methods with a special-case: when getting elements
|
|
1672
|
+
at positions `0` or `-1` (i.e. `.first()` / `.last()`) these _can_ resolve before the
|
|
1673
|
+
parent `<promise-iter>`.
|
|
1674
|
+
|
|
1675
|
+
XXX
|
|
1676
|
+
|
|
1677
|
+
|
|
1678
|
+
#### Array proxy methods returning `<promise-iter>`
|
|
1679
|
+
|
|
1680
|
+
- `<promise-iter>.sort(..)`
|
|
1681
|
+
- `<promise-iter>.slice(..)`
|
|
1682
|
+
- `<promise-iter>.entries()` / `<promise-iter>.keys()` / `<promise-iter>.values()`
|
|
1683
|
+
|
|
1684
|
+
These methods are proxies to the appropriate array methods.
|
|
1685
|
+
|
|
1686
|
+
```bnf
|
|
1687
|
+
<promise-iter>.<method>(..)
|
|
1688
|
+
-> <promise-iter>
|
|
1689
|
+
```
|
|
1690
|
+
|
|
1691
|
+
These methods need the parent `<promise-iter>` to resolve before resolving themselves.
|
|
1692
|
+
|
|
1693
|
+
XXX links...
|
|
1694
|
+
|
|
1695
|
+
|
|
1696
|
+
#### Array proxy methods returning a `<promise>`
|
|
1697
|
+
|
|
1698
|
+
- `<promise-iter>.indexOf(..)`
|
|
1699
|
+
- `<promise-iter>.includes(..)`
|
|
1700
|
+
- `<promise-iter>.every(..)` / `<promise-iter>.some(..)`
|
|
1701
|
+
|
|
1702
|
+
These methods are proxies to the appropriate array methods.
|
|
1703
|
+
|
|
1704
|
+
```bnf
|
|
1705
|
+
<promise-iter>.<method>(..)
|
|
1706
|
+
-> <promise>
|
|
1707
|
+
```
|
|
1708
|
+
|
|
1709
|
+
These methods need the parent `<promise-iter>` to resolve before resolving themselves.
|
|
1710
|
+
|
|
1711
|
+
Since the equivalent array methods do not return iterables these will return a basic
|
|
1712
|
+
(non-iterable) `<promise>`.
|
|
1713
|
+
|
|
1714
|
+
XXX links...
|
|
1715
|
+
|
|
1716
|
+
|
|
1666
1717
|
#### `<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`
|
|
1667
1718
|
|
|
1668
1719
|
An extension to
|