ig-types 6.25.3 → 6.26.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/Number.js +103 -0
- package/Promise.js +1 -0
- package/main.js +1 -0
- package/package.json +1 -1
- package/Promise.js.new +0 -1127
package/Number.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**********************************************************************
|
|
2
|
+
*
|
|
3
|
+
*
|
|
4
|
+
**********************************************/ /* c8 ignore next 2 */
|
|
5
|
+
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
6
|
+
(function(require){ var module={} // make module AMD/node compatible...
|
|
7
|
+
/*********************************************************************/
|
|
8
|
+
|
|
9
|
+
var object = require('ig-object')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
//---------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
var NumberMixin =
|
|
15
|
+
module.NumberMixin =
|
|
16
|
+
object.Mixin('NumberMixin', 'soft', {
|
|
17
|
+
toAlpha: function(n, alpha='abcdefghijklmnopqrstuvwxyz'){
|
|
18
|
+
var res = ''
|
|
19
|
+
var base = alpha.length
|
|
20
|
+
do{
|
|
21
|
+
res = alpha[n % base] + res
|
|
22
|
+
n = Math.floor(n/base) - 1
|
|
23
|
+
}while(n >= 0)
|
|
24
|
+
return res },
|
|
25
|
+
fromAlpha: function(str, alpha='abcdefghijklmnopqrstuvwxyz'){
|
|
26
|
+
var res = 0
|
|
27
|
+
var base = alpha.length
|
|
28
|
+
var i = 0
|
|
29
|
+
for(var c of [...str].reverse()){
|
|
30
|
+
var val = alpha.indexOf(c) + 1
|
|
31
|
+
res += val * (base ** i++) }
|
|
32
|
+
return res-1 },
|
|
33
|
+
|
|
34
|
+
toRoman: function(n){
|
|
35
|
+
var index = {
|
|
36
|
+
M: 1000,
|
|
37
|
+
CM: 900,
|
|
38
|
+
D: 500,
|
|
39
|
+
CD: 400,
|
|
40
|
+
C: 100,
|
|
41
|
+
XC: 90,
|
|
42
|
+
L: 50,
|
|
43
|
+
XL: 40,
|
|
44
|
+
X: 10,
|
|
45
|
+
IX: 9,
|
|
46
|
+
V: 5,
|
|
47
|
+
IV: 4,
|
|
48
|
+
I: 1,
|
|
49
|
+
}
|
|
50
|
+
var res = ''
|
|
51
|
+
for(var R in index){
|
|
52
|
+
while(n >= index[R]){
|
|
53
|
+
res += R
|
|
54
|
+
n -= index[R] } }
|
|
55
|
+
return res },
|
|
56
|
+
fromRoman: function(str){
|
|
57
|
+
var index = {
|
|
58
|
+
M: 1000,
|
|
59
|
+
CM: 900,
|
|
60
|
+
D: 500,
|
|
61
|
+
CD: 400,
|
|
62
|
+
C: 100,
|
|
63
|
+
XC: 90,
|
|
64
|
+
L: 50,
|
|
65
|
+
XL: 40,
|
|
66
|
+
X: 10,
|
|
67
|
+
IX: 9,
|
|
68
|
+
V: 5,
|
|
69
|
+
IV: 4,
|
|
70
|
+
I: 1,
|
|
71
|
+
}
|
|
72
|
+
var n = 0
|
|
73
|
+
str = str.toUpperCase()
|
|
74
|
+
while(str != ''){
|
|
75
|
+
if(str.slice(0, 2) in index){
|
|
76
|
+
n += index[str.slice(0, 2)]
|
|
77
|
+
str = str.slice(2)
|
|
78
|
+
} else if(str[0] in index){
|
|
79
|
+
n += index[str[0]]
|
|
80
|
+
str = str.slice(1)
|
|
81
|
+
} else {
|
|
82
|
+
throw new Error('fromRoman(..): Unknown sequence: '+ str) } }
|
|
83
|
+
return n },
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
NumberMixin(Number)
|
|
87
|
+
|
|
88
|
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
89
|
+
var NumberProtoMixin =
|
|
90
|
+
module.NumberProtoMixin =
|
|
91
|
+
object.Mixin('NumberProtoMixin', 'soft', {
|
|
92
|
+
toAlpha: function(alpha='abcdefghijklmnopqrstuvwxyz'){
|
|
93
|
+
return this.constructor.toAlpha(this, alpha) },
|
|
94
|
+
toRoman: function(n){
|
|
95
|
+
return this.constructor.toRoman(this) },
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
NumberProtoMixin(Number.prototype)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
/**********************************************************************
|
|
103
|
+
* vim:set ts=4 sw=4 nowrap : */ return module })
|
package/Promise.js
CHANGED
|
@@ -1388,6 +1388,7 @@ object.Mixin('PromiseMixin', 'soft', {
|
|
|
1388
1388
|
// XXX should we just check for .then(..) ???
|
|
1389
1389
|
// XXX update README if this changes...
|
|
1390
1390
|
: (data.length == 1
|
|
1391
|
+
&& data[0]
|
|
1391
1392
|
&& data[0][Symbol.asyncIterator]
|
|
1392
1393
|
&& data[0].then) ?
|
|
1393
1394
|
data[0].then(func, ...error)
|
package/main.js
CHANGED
package/package.json
CHANGED
package/Promise.js.new
DELETED
|
@@ -1,1127 +0,0 @@
|
|
|
1
|
-
/**********************************************************************
|
|
2
|
-
*
|
|
3
|
-
* This defines the following extensions to Promise:
|
|
4
|
-
*
|
|
5
|
-
* Promise.iter(seq)
|
|
6
|
-
* <promise>.iter()
|
|
7
|
-
* Iterable promise object.
|
|
8
|
-
* Similar to Promise.all(..) but adds basic iterator API.
|
|
9
|
-
*
|
|
10
|
-
* Promise.interactive(handler)
|
|
11
|
-
* Interactive promise object.
|
|
12
|
-
* This adds a basic message passing API to the promise.
|
|
13
|
-
*
|
|
14
|
-
* Promise.cooperative()
|
|
15
|
-
* Cooperative promise object.
|
|
16
|
-
* Exposes the API to resolve/reject the promise object
|
|
17
|
-
* externally.
|
|
18
|
-
*
|
|
19
|
-
* <promise>.as(obj)
|
|
20
|
-
* Promise proxy.
|
|
21
|
-
* Proxies the methods available from obj to promise value.
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
**********************************************/ /* c8 ignore next 2 */
|
|
27
|
-
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
28
|
-
(function(require){ var module={} // make module AMD/node compatible...
|
|
29
|
-
/*********************************************************************/
|
|
30
|
-
|
|
31
|
-
var object = require('ig-object')
|
|
32
|
-
|
|
33
|
-
var generator = require('./generator')
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
//---------------------------------------------------------------------
|
|
38
|
-
// Iterable promise...
|
|
39
|
-
//
|
|
40
|
-
// Like Promise.all(..) but adds ability to iterate through results
|
|
41
|
-
// via generators .map(..)/.reduce(..) and friends...
|
|
42
|
-
//
|
|
43
|
-
// NOTE: the following can not be implemented here:
|
|
44
|
-
// .splice(..) - can't both modify and return
|
|
45
|
-
// a result...
|
|
46
|
-
// .pop() / .shift() - can't modify the promise, use
|
|
47
|
-
// .first() / .last() instead.
|
|
48
|
-
// [Symbol.iterator]() - needs to be sync and we can't
|
|
49
|
-
// know the number of elements to
|
|
50
|
-
// return promises before the whole
|
|
51
|
-
// iterable promise is resolved.
|
|
52
|
-
// NOTE: we are not using async/await here as we need to control the
|
|
53
|
-
// type of promise returned in cases where we know we are returning
|
|
54
|
-
// an array...
|
|
55
|
-
// NOTE: there is no point in implementing a 1:1 version of this that
|
|
56
|
-
// would not support element expansion/contraction as it would only
|
|
57
|
-
// simplify a couple of methods that are 1:1 (like .map(..) and
|
|
58
|
-
// .some(..)) while methods like .filter(..) will throw everything
|
|
59
|
-
// back to the complex IterablePromise...
|
|
60
|
-
//
|
|
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...
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
var iterPromiseProxy =
|
|
67
|
-
module.iterPromiseProxy =
|
|
68
|
-
function(name){
|
|
69
|
-
return function(...args){
|
|
70
|
-
return this.constructor(
|
|
71
|
-
this.then(function(lst){
|
|
72
|
-
return lst[name](...args) })) } }
|
|
73
|
-
|
|
74
|
-
// XXX ASYNC should this be async or simply return a SyncPromise/Promise???
|
|
75
|
-
var promiseProxy =
|
|
76
|
-
module.promiseProxy =
|
|
77
|
-
function(name){
|
|
78
|
-
return async function(...args){
|
|
79
|
-
return (await this)[name](...args) } }
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
var IterablePromise =
|
|
83
|
-
module.IterablePromise =
|
|
84
|
-
object.Constructor('IterablePromise', Promise, {
|
|
85
|
-
get STOP(){
|
|
86
|
-
return Array.STOP },
|
|
87
|
-
|
|
88
|
-
}, {
|
|
89
|
-
// packed array...
|
|
90
|
-
//
|
|
91
|
-
// Holds promise state.
|
|
92
|
-
//
|
|
93
|
-
// Format:
|
|
94
|
-
// [
|
|
95
|
-
// <non-array-value>,
|
|
96
|
-
// [ <value> ],
|
|
97
|
-
// <promise>,
|
|
98
|
-
// ...
|
|
99
|
-
// ]
|
|
100
|
-
//
|
|
101
|
-
// This format has several useful features:
|
|
102
|
-
// - concatenating packed lists results in a packed list
|
|
103
|
-
// - adding an iterable promise (as-is) into a packed list results
|
|
104
|
-
// in a packed list
|
|
105
|
-
//
|
|
106
|
-
// NOTE: in general iterable promises are implicitly immutable, so
|
|
107
|
-
// it is not recomended to ever edit this in-place...
|
|
108
|
-
// NOTE: we are not isolating or "protecting" any internals to
|
|
109
|
-
// enable users to responsibly extend the code.
|
|
110
|
-
__packed: null,
|
|
111
|
-
|
|
112
|
-
// low-level .__packed handlers/helpers...
|
|
113
|
-
//
|
|
114
|
-
// NOTE: these can be useful for debugging and extending...
|
|
115
|
-
//
|
|
116
|
-
// pack and oprionally transform/handle an array (sync)...
|
|
117
|
-
//
|
|
118
|
-
// NOTE: if 'types/Array' is imported this will support throwing STOP
|
|
119
|
-
// from the handler.
|
|
120
|
-
// Due to the async nature of promises though the way stops are
|
|
121
|
-
// handled may be unpredictable -- the handlers can be run out
|
|
122
|
-
// of order, as the nested promises resolve and thus throwing
|
|
123
|
-
// stop will stop the handlers not yet run and not the next
|
|
124
|
-
// handlers in sequence.
|
|
125
|
-
// XXX EXPEREMENTAL: STOP...
|
|
126
|
-
// XXX ITER can we unwind (sync/async) generators one by one???
|
|
127
|
-
__pack: function(list, handler=undefined, onerror=undefined){
|
|
128
|
-
var that = this
|
|
129
|
-
// handle iterator...
|
|
130
|
-
// XXX ITER do we unwind the iterator here or wait to unwind later???
|
|
131
|
-
if(typeof(list) == 'object'
|
|
132
|
-
&& Symbol.iterator in list){
|
|
133
|
-
if(!onerror){
|
|
134
|
-
list = [...list]
|
|
135
|
-
// handle errors in input generator...
|
|
136
|
-
// NOTE: this does not offer the most control because semantically
|
|
137
|
-
// we bust behave in the same manner as <generator>.iter(..)
|
|
138
|
-
} else {
|
|
139
|
-
var res = []
|
|
140
|
-
try{
|
|
141
|
-
for(var e of list){
|
|
142
|
-
res.push(e) }
|
|
143
|
-
}catch(err){
|
|
144
|
-
var r = onerror(err)
|
|
145
|
-
r !== undefined
|
|
146
|
-
&& res.push(r) }
|
|
147
|
-
list = res } }
|
|
148
|
-
// handle iterable promise...
|
|
149
|
-
if(list instanceof IterablePromise){
|
|
150
|
-
return this.__handle(list.__packed, handler, onerror) }
|
|
151
|
-
// handle promise / async-iterator...
|
|
152
|
-
// XXX ITER do we unwind the iterator here or wait to unwind later???
|
|
153
|
-
if(typeof(list) == 'object'
|
|
154
|
-
&& Symbol.asyncIterator in list){
|
|
155
|
-
return list
|
|
156
|
-
.iter(handler, onerror)
|
|
157
|
-
.then(function(list){
|
|
158
|
-
return that.__pack(list) }) }
|
|
159
|
-
if(list instanceof Promise){
|
|
160
|
-
return list
|
|
161
|
-
.then(function(list){
|
|
162
|
-
return that.__pack(list, handler, onerror) }) }
|
|
163
|
-
// do the work...
|
|
164
|
-
// NOTE: packing and handling are mixed here because it's faster
|
|
165
|
-
// to do them both on a single list traverse...
|
|
166
|
-
handler = handler
|
|
167
|
-
?? function(elem){
|
|
168
|
-
return [elem] }
|
|
169
|
-
return that.__handle([list].flat(), handler, onerror) },
|
|
170
|
-
// transform/handle packed array (sync, but can return promises in the list)...
|
|
171
|
-
__handle: function(list, handler=undefined, onerror=undefined){
|
|
172
|
-
var that = this
|
|
173
|
-
if(typeof(list) == 'function'){
|
|
174
|
-
handler = list
|
|
175
|
-
list = this.__packed }
|
|
176
|
-
if(!handler){
|
|
177
|
-
return list }
|
|
178
|
-
// handle promise list...
|
|
179
|
-
if(list instanceof Promise){
|
|
180
|
-
return list.then(function(list){
|
|
181
|
-
return that.__handle(list, handler, onerror) }) }
|
|
182
|
-
// do the work...
|
|
183
|
-
// NOTE: since each section of the packed .__array is the same
|
|
184
|
-
// structure as the input we'll use .__pack(..) to handle
|
|
185
|
-
// them, this also keeps all the handling code in one place.
|
|
186
|
-
var stop = false
|
|
187
|
-
var map = 'map'
|
|
188
|
-
var pack = function(){
|
|
189
|
-
return [list].flat()
|
|
190
|
-
[map](function(elem){
|
|
191
|
-
// XXX EXPEREMENTAL...
|
|
192
|
-
return elem instanceof IterablePromise ?
|
|
193
|
-
(elem.isSync() ?
|
|
194
|
-
handler(elem.sync())
|
|
195
|
-
// XXX need to handle this but keep it IterablePromise...
|
|
196
|
-
: elem.iterthen(handler))
|
|
197
|
-
: (elem instanceof SyncPromise
|
|
198
|
-
&& !(elem.sync() instanceof Promise)) ?
|
|
199
|
-
handler(elem.sync())
|
|
200
|
-
: elem && elem.then ?
|
|
201
|
-
(handleSTOP ?
|
|
202
|
-
// stoppable -- need to handle stop async...
|
|
203
|
-
elem
|
|
204
|
-
.then(function(res){
|
|
205
|
-
return !stop ?
|
|
206
|
-
handler(res)
|
|
207
|
-
: [] })
|
|
208
|
-
// NOTE: we are using .catch(..) here
|
|
209
|
-
// instead of directly passing the
|
|
210
|
-
// error handler to be able to catch
|
|
211
|
-
// the STOP from the handler...
|
|
212
|
-
.catch(handleSTOP)
|
|
213
|
-
// non-stoppable...
|
|
214
|
-
: elem.then(handler))
|
|
215
|
-
: elem instanceof Array ?
|
|
216
|
-
handler(elem)
|
|
217
|
-
: handler(elem) }) }
|
|
218
|
-
// pack (stoppable)...
|
|
219
|
-
if(!!this.constructor.STOP){
|
|
220
|
-
map = 'smap'
|
|
221
|
-
var handleSTOP = function(err){
|
|
222
|
-
// handle stop...
|
|
223
|
-
stop = err
|
|
224
|
-
if(err === that.constructor.STOP
|
|
225
|
-
|| err instanceof that.constructor.STOP){
|
|
226
|
-
return 'value' in err ?
|
|
227
|
-
err.value
|
|
228
|
-
: [] }
|
|
229
|
-
throw err }
|
|
230
|
-
try{
|
|
231
|
-
return pack()
|
|
232
|
-
}catch(err){
|
|
233
|
-
return handleSTOP(err) } }
|
|
234
|
-
// pack (non-stoppable)...
|
|
235
|
-
return pack() },
|
|
236
|
-
// XXX this should return IterablePromise if .__packed is partially sync (???)
|
|
237
|
-
// unpack array (sync/async)...
|
|
238
|
-
__unpack: function(list){
|
|
239
|
-
list = list
|
|
240
|
-
?? this.__packed
|
|
241
|
-
// handle promise list...
|
|
242
|
-
if(list instanceof IterablePromise){
|
|
243
|
-
return list.__unpack() }
|
|
244
|
-
if(list instanceof Promise){
|
|
245
|
-
return list
|
|
246
|
-
.then(this.__unpack.bind(this)) }
|
|
247
|
-
var res = []
|
|
248
|
-
for(var e of list){
|
|
249
|
-
if(e instanceof IterablePromise){
|
|
250
|
-
e = e.__unpack() }
|
|
251
|
-
if(e instanceof SyncPromise){
|
|
252
|
-
e = e.sync() }
|
|
253
|
-
// give up on a sync solution...
|
|
254
|
-
if(e instanceof Promise){
|
|
255
|
-
// XXX can we return an IterablePromise???
|
|
256
|
-
// XXX this will cause infinite recursion....
|
|
257
|
-
//return Promise.iter(list).flat() }
|
|
258
|
-
// XXX is there a more elegant way to do this???
|
|
259
|
-
return Promise.all(list)
|
|
260
|
-
.then(function(list){
|
|
261
|
-
return list.flat() })
|
|
262
|
-
.iter() }
|
|
263
|
-
//return Promise.all(list)
|
|
264
|
-
// .then(function(list){
|
|
265
|
-
// return list.flat() }) }
|
|
266
|
-
res.push(e) }
|
|
267
|
-
return res.flat() },
|
|
268
|
-
|
|
269
|
-
[Symbol.asyncIterator]: async function*(){
|
|
270
|
-
var list = this.__packed
|
|
271
|
-
if(list instanceof Promise){
|
|
272
|
-
yield* await this.__unpack(list)
|
|
273
|
-
return }
|
|
274
|
-
for await(var elem of list){
|
|
275
|
-
yield* elem instanceof Array ?
|
|
276
|
-
elem
|
|
277
|
-
: [elem] } },
|
|
278
|
-
|
|
279
|
-
// iterator methods...
|
|
280
|
-
//
|
|
281
|
-
// These will return a new IterablePromise instance...
|
|
282
|
-
//
|
|
283
|
-
// NOTE: these are different to Array's equivalents in that the handler
|
|
284
|
-
// is called not in the order of the elements but rather in order
|
|
285
|
-
// of promise resolution...
|
|
286
|
-
// NOTE: index of items is unknowable because items can expand and
|
|
287
|
-
// contract depending on handlers (e.g. .filter(..) can remove
|
|
288
|
-
// items)...
|
|
289
|
-
map: function(func){
|
|
290
|
-
return this.constructor(this,
|
|
291
|
-
function(e){
|
|
292
|
-
var res = func(e)
|
|
293
|
-
return res instanceof Promise ?
|
|
294
|
-
res.then(function(e){
|
|
295
|
-
return [e] })
|
|
296
|
-
: [res] }) },
|
|
297
|
-
filter: function(func){
|
|
298
|
-
return this.constructor(this,
|
|
299
|
-
function(e){
|
|
300
|
-
var res = func(e)
|
|
301
|
-
var _filter = function(elem){
|
|
302
|
-
return res ?
|
|
303
|
-
[elem]
|
|
304
|
-
: [] }
|
|
305
|
-
return res instanceof Promise ?
|
|
306
|
-
res.then(_filter)
|
|
307
|
-
: _filter(e) }) },
|
|
308
|
-
// NOTE: this does not return an iterable promise as we can't know
|
|
309
|
-
// what the user reduces to...
|
|
310
|
-
// NOTE: the items can be handled out of order because the nested
|
|
311
|
-
// promises can resolve in any order...
|
|
312
|
-
// NOTE: since order of execution can not be guaranteed there is no
|
|
313
|
-
// point in implementing .reduceRight(..) in the same way
|
|
314
|
-
// (see below)...
|
|
315
|
-
reduce: function(func, res){
|
|
316
|
-
return this.constructor(this,
|
|
317
|
-
function(e){
|
|
318
|
-
res = func(res, e)
|
|
319
|
-
return [] })
|
|
320
|
-
.then(function(){
|
|
321
|
-
return res }) },
|
|
322
|
-
|
|
323
|
-
// XXX BETWEEN...
|
|
324
|
-
between: function(func){
|
|
325
|
-
var i = 0
|
|
326
|
-
var j = 0
|
|
327
|
-
var prev
|
|
328
|
-
return this.constructor(this,
|
|
329
|
-
function(e){
|
|
330
|
-
return i++ > 0 ?
|
|
331
|
-
[
|
|
332
|
-
typeof(func) == 'function' ?
|
|
333
|
-
func.call(this, [prev, e], i, i + j++)
|
|
334
|
-
: func,
|
|
335
|
-
e,
|
|
336
|
-
]
|
|
337
|
-
: [e] }) },
|
|
338
|
-
|
|
339
|
-
// XXX .chain(..) -- see generator.chain(..)
|
|
340
|
-
|
|
341
|
-
flat: function(depth=1){
|
|
342
|
-
return this.constructor(this,
|
|
343
|
-
function(e){
|
|
344
|
-
return (depth > 1
|
|
345
|
-
&& e != null
|
|
346
|
-
&& e.flat) ?
|
|
347
|
-
e.flat(depth-1)
|
|
348
|
-
: depth != 0 ?
|
|
349
|
-
e
|
|
350
|
-
: [e] }) },
|
|
351
|
-
reverse: function(){
|
|
352
|
-
var lst = this.__packed
|
|
353
|
-
return this.constructor(
|
|
354
|
-
lst instanceof Promise ?
|
|
355
|
-
lst.then(function(elems){
|
|
356
|
-
return elems instanceof Array ?
|
|
357
|
-
elems.slice()
|
|
358
|
-
.reverse()
|
|
359
|
-
: elems })
|
|
360
|
-
: lst
|
|
361
|
-
.map(function(elems){
|
|
362
|
-
return elems instanceof Array ?
|
|
363
|
-
elems.slice()
|
|
364
|
-
.reverse()
|
|
365
|
-
: elems instanceof Promise ?
|
|
366
|
-
elems.then(function(elems){
|
|
367
|
-
return elems.reverse() })
|
|
368
|
-
: elems })
|
|
369
|
-
.reverse(),
|
|
370
|
-
'raw') },
|
|
371
|
-
|
|
372
|
-
// NOTE: the following methods can create an unresolved promise from
|
|
373
|
-
// a resolved promise...
|
|
374
|
-
concat: function(other){
|
|
375
|
-
var that = this
|
|
376
|
-
var cur = this.__pack(this)
|
|
377
|
-
var other = this.__pack(other)
|
|
378
|
-
return this.constructor(
|
|
379
|
-
// NOTE: we need to keep things as exposed as possible, this
|
|
380
|
-
// is why we're not blanketing all the cases with
|
|
381
|
-
// Promise.all(..)...
|
|
382
|
-
(cur instanceof Promise
|
|
383
|
-
&& other instanceof Promise) ?
|
|
384
|
-
[cur, other]
|
|
385
|
-
: cur instanceof Promise ?
|
|
386
|
-
[cur, ...other]
|
|
387
|
-
: other instanceof Promise ?
|
|
388
|
-
[...cur, other]
|
|
389
|
-
: [...cur, ...other],
|
|
390
|
-
'raw') },
|
|
391
|
-
push: function(elem){
|
|
392
|
-
return this.concat([elem]) },
|
|
393
|
-
unshift: function(elem){
|
|
394
|
-
return this.constructor([elem])
|
|
395
|
-
.concat(this) },
|
|
396
|
-
|
|
397
|
-
// proxy methods...
|
|
398
|
-
//
|
|
399
|
-
// These require the whole promise to resolve to trigger.
|
|
400
|
-
//
|
|
401
|
-
// An exception to this would be .at(0)/.first() and .at(-1)/.last()
|
|
402
|
-
// that can get the target element if it's accessible.
|
|
403
|
-
//
|
|
404
|
-
// NOTE: methods that are guaranteed to return an array will return
|
|
405
|
-
// an iterable promise (created with iterPromiseProxy(..))...
|
|
406
|
-
//
|
|
407
|
-
// XXX ASYNC should this be async or simply return a SyncPromise/Promise???
|
|
408
|
-
at: async function(i){
|
|
409
|
-
var list = this.__packed
|
|
410
|
-
return ((i != 0 && i != -1)
|
|
411
|
-
|| list instanceof Promise
|
|
412
|
-
// XXX not sure if this is correct...
|
|
413
|
-
|| list.at(i) instanceof Promise) ?
|
|
414
|
-
(await this).at(i)
|
|
415
|
-
// NOTE: we can only reason about first/last explicit elements,
|
|
416
|
-
// anything else is non-deterministic...
|
|
417
|
-
: list.at(i) instanceof Promise ?
|
|
418
|
-
[await list.at(i)].flat().at(i)
|
|
419
|
-
: list.at(i) instanceof Array ?
|
|
420
|
-
list.at(i).at(i)
|
|
421
|
-
: list.at(i) },
|
|
422
|
-
first: function(){
|
|
423
|
-
return this.at(0) },
|
|
424
|
-
last: function(){
|
|
425
|
-
return this.at(-1) },
|
|
426
|
-
|
|
427
|
-
// NOTE: unlike .reduce(..) this needs the parent fully resolved
|
|
428
|
-
// to be able to iterate from the end.
|
|
429
|
-
// XXX is it faster to do .reverse().reduce(..) ???
|
|
430
|
-
reduceRight: promiseProxy('reduceRight'),
|
|
431
|
-
|
|
432
|
-
// NOTE: there is no way we can do a sync generator returning
|
|
433
|
-
// promises for values because any promise in .__packed makes
|
|
434
|
-
// the value count/index non-deterministic...
|
|
435
|
-
sort: iterPromiseProxy('sort'),
|
|
436
|
-
slice: iterPromiseProxy('slice'),
|
|
437
|
-
|
|
438
|
-
entries: iterPromiseProxy('entries'),
|
|
439
|
-
keys: iterPromiseProxy('keys'),
|
|
440
|
-
values: iterPromiseProxy('values'),
|
|
441
|
-
|
|
442
|
-
indexOf: promiseProxy('indexOf'),
|
|
443
|
-
lastIndexOf: promiseProxy('lastIndexOf'),
|
|
444
|
-
includes: promiseProxy('includes'),
|
|
445
|
-
|
|
446
|
-
//
|
|
447
|
-
// .find(<func>)
|
|
448
|
-
// .find(<func>, 'value')
|
|
449
|
-
// -> <promise>(<value>)
|
|
450
|
-
//
|
|
451
|
-
// .find(<func>, 'result')
|
|
452
|
-
// -> <promise>(<result>)
|
|
453
|
-
//
|
|
454
|
-
// .find(<func>, 'bool')
|
|
455
|
-
// -> <promise>(<bool>)
|
|
456
|
-
//
|
|
457
|
-
// NOTE: this is slightly different to Array's .find(..) in that it
|
|
458
|
-
// accepts the result value enabling returning both the value
|
|
459
|
-
// itself ('value', default), the test function's result
|
|
460
|
-
// ('result') or true/false ('bool') -- this is added to be
|
|
461
|
-
// able to distinguish between the undefined as a stored value
|
|
462
|
-
// and undefined as a "nothing found" result.
|
|
463
|
-
// NOTE: I do not get how essentially identical methods .some(..)
|
|
464
|
-
// and .find(..) got added to JS's Array...
|
|
465
|
-
// the only benefit is that .some(..) handles undefined values
|
|
466
|
-
// stored in the array better...
|
|
467
|
-
// NOTE: this will return the result as soon as it's available but
|
|
468
|
-
// it will not stop the created but unresolved at the time
|
|
469
|
-
// promises from executing, this is both good and bad:
|
|
470
|
-
// + it will not break other clients waiting for promises
|
|
471
|
-
// to resolve...
|
|
472
|
-
// - if no clients are available this can lead to wasted
|
|
473
|
-
// CPU time...
|
|
474
|
-
//
|
|
475
|
-
// XXX ASYNC should this be async or simply return a SyncPromise/Promise???
|
|
476
|
-
find: async function(func, result='value'){
|
|
477
|
-
var that = this
|
|
478
|
-
// NOTE: not using pure await here as this is simpler to actually
|
|
479
|
-
// control the moment the resulting promise resolves without
|
|
480
|
-
// the need for juggling state...
|
|
481
|
-
return new Promise(function(resolve, reject){
|
|
482
|
-
var resolved = false
|
|
483
|
-
that.map(function(elem){
|
|
484
|
-
var res = func(elem)
|
|
485
|
-
if(res){
|
|
486
|
-
resolved = true
|
|
487
|
-
resolve(
|
|
488
|
-
result == 'bool' ?
|
|
489
|
-
true
|
|
490
|
-
: result == 'result' ?
|
|
491
|
-
res
|
|
492
|
-
: elem)
|
|
493
|
-
// XXX EXPEREMENTAL: STOP...
|
|
494
|
-
// NOTE: we do not need to throw STOP here
|
|
495
|
-
// but it can prevent some overhead...
|
|
496
|
-
if(that.constructor.STOP){
|
|
497
|
-
throw that.constructor.STOP } } })
|
|
498
|
-
.then(function(){
|
|
499
|
-
resolved
|
|
500
|
-
|| resolve(
|
|
501
|
-
result == 'bool' ?
|
|
502
|
-
false
|
|
503
|
-
: undefined) }) }) },
|
|
504
|
-
findIndex: promiseProxy('findIndex'),
|
|
505
|
-
|
|
506
|
-
// NOTE: this is just a special-case of .find(..)
|
|
507
|
-
// XXX ASYNC should this be async or simply return a SyncPromise/Promise???
|
|
508
|
-
some: async function(func){
|
|
509
|
-
return this.find(func, 'bool') },
|
|
510
|
-
every: promiseProxy('every'),
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
// XXX ASYNC should this be async or simply return a SyncPromise/Promise???
|
|
514
|
-
join: async function(){
|
|
515
|
-
return [...(await this)]
|
|
516
|
-
.join(...arguments) },
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
// this is defined globally as Promise.prototype.iter(..)
|
|
520
|
-
//
|
|
521
|
-
// for details see: PromiseMixin(..) below...
|
|
522
|
-
//iter: function(handler=undefined){ ... },
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
// promise api...
|
|
526
|
-
//
|
|
527
|
-
// Overload .then(..), .catch(..) and .finally(..) to return a plain
|
|
528
|
-
// Promise instnace...
|
|
529
|
-
//
|
|
530
|
-
// NOTE: .catch(..) and .finally(..) are implemented through .then(..)
|
|
531
|
-
// so we do not need to overload those...
|
|
532
|
-
// NOTE: this is slightly different from .then(..) in that it can be
|
|
533
|
-
// called without arguments and return a promise wrapper. This can
|
|
534
|
-
// be useful to hide special promise functionality...
|
|
535
|
-
//
|
|
536
|
-
// NOTE: this is internally linked to the actual (via: ..then.call(this, ..))
|
|
537
|
-
// state and will be resolved in .__new__(..) below.
|
|
538
|
-
then: function(onfulfilled, onrejected){
|
|
539
|
-
var p = new Promise(
|
|
540
|
-
function(resolve, reject){
|
|
541
|
-
Promise.prototype.then.call(this,
|
|
542
|
-
// NOTE: resolve(..) / reject(..) return undefined so
|
|
543
|
-
// we can't pass them directly here...
|
|
544
|
-
function(res){
|
|
545
|
-
resolve(res)
|
|
546
|
-
return res },
|
|
547
|
-
function(res){
|
|
548
|
-
reject(res)
|
|
549
|
-
return res }) }.bind(this))
|
|
550
|
-
return arguments.length > 0 ?
|
|
551
|
-
p.then(...arguments)
|
|
552
|
-
: p },
|
|
553
|
-
// XXX EXPEREMENTAL revise...
|
|
554
|
-
// Like .then(..) but returns an IterablePromise instance...
|
|
555
|
-
iterthen: function(onfulfilled, onrejected){
|
|
556
|
-
if(this.isSync()){
|
|
557
|
-
var res = onfulfilled ?
|
|
558
|
-
this.constructor(onfulfilled(this.__unpack()))
|
|
559
|
-
: this.constructor(this.__unpack())
|
|
560
|
-
onrejected
|
|
561
|
-
&& res.catch(onrejected)
|
|
562
|
-
return res }
|
|
563
|
-
// XXX we need to feed the output of onfulfilled to the value of
|
|
564
|
-
// res, but to this without wrapping the whole thing in a
|
|
565
|
-
// promise (possible???)...
|
|
566
|
-
return arguments.length > 0 ?
|
|
567
|
-
this.constructor(this.then(...arguments))
|
|
568
|
-
: this.constructor(this.__packed, 'raw') },
|
|
569
|
-
|
|
570
|
-
// XXX EXPEREMENTAL
|
|
571
|
-
isSync: function(){
|
|
572
|
-
return !(this.__packed instanceof Promise
|
|
573
|
-
|| this.__packed
|
|
574
|
-
.filter(function(e){
|
|
575
|
-
return e instanceof IterablePromise ?
|
|
576
|
-
!e.isSync()
|
|
577
|
-
: e instanceof Promise
|
|
578
|
-
&& !(e instanceof SyncPromise) })
|
|
579
|
-
.length > 0) },
|
|
580
|
-
sync: function(error=false){
|
|
581
|
-
try{
|
|
582
|
-
var res = this.__unpack()
|
|
583
|
-
}catch(err){
|
|
584
|
-
if(error == false){
|
|
585
|
-
return }
|
|
586
|
-
if(typeof(error) == 'function'){
|
|
587
|
-
return error(err) }
|
|
588
|
-
throw err }
|
|
589
|
-
return error !== false
|
|
590
|
-
&& res instanceof Promise ?
|
|
591
|
-
// XXX should this be an IterablePromise???
|
|
592
|
-
res.catch(error)
|
|
593
|
-
: res },
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
// constructor...
|
|
597
|
-
//
|
|
598
|
-
// Promise.iter([ .. ])
|
|
599
|
-
// -> iterable-promise
|
|
600
|
-
//
|
|
601
|
-
// Promise.iter([ .. ], handler)
|
|
602
|
-
// -> iterable-promise
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
// handler(e)
|
|
606
|
-
// -> [value, ..]
|
|
607
|
-
// -> []
|
|
608
|
-
// -> <promise>
|
|
609
|
-
//
|
|
610
|
-
//
|
|
611
|
-
// NOTE: element index is unknowable until the full list is expanded
|
|
612
|
-
// as handler(..)'s return value can expand to any number of
|
|
613
|
-
// items...
|
|
614
|
-
// XXX we can make the index a promise, then if the client needs
|
|
615
|
-
// the value they can wait for it...
|
|
616
|
-
// ...this may be quite an overhead...
|
|
617
|
-
//
|
|
618
|
-
//
|
|
619
|
-
// Special cases useful for extending this constructor...
|
|
620
|
-
//
|
|
621
|
-
// Set raw .__packed without any pre-processing...
|
|
622
|
-
// Promise.iter([ .. ], 'raw')
|
|
623
|
-
// -> iterable-promise
|
|
624
|
-
//
|
|
625
|
-
// Create a rejected iterator...
|
|
626
|
-
// Promise.iter(false)
|
|
627
|
-
// -> iterable-promise
|
|
628
|
-
//
|
|
629
|
-
//
|
|
630
|
-
// NOTE: if 'types/Array' is imported this will support throwing STOP,
|
|
631
|
-
// for more info see notes for .__pack(..)
|
|
632
|
-
// XXX EXPEREMENTAL: STOP...
|
|
633
|
-
__new__: function(_, list, handler=undefined, onerror=undefined){
|
|
634
|
-
// instance...
|
|
635
|
-
var promise
|
|
636
|
-
var obj = Reflect.construct(
|
|
637
|
-
IterablePromise.__proto__,
|
|
638
|
-
[function(resolve, reject){
|
|
639
|
-
// NOTE: this is here for Promise compatibility...
|
|
640
|
-
if(typeof(list) == 'function'){
|
|
641
|
-
return list.call(this, ...arguments) }
|
|
642
|
-
// initial reject...
|
|
643
|
-
if(list === false){
|
|
644
|
-
return reject() }
|
|
645
|
-
promise = {resolve, reject} }],
|
|
646
|
-
IterablePromise)
|
|
647
|
-
|
|
648
|
-
// populate new instance...
|
|
649
|
-
if(promise){
|
|
650
|
-
// handle/pack input data...
|
|
651
|
-
if(handler != 'raw'){
|
|
652
|
-
list = list instanceof IterablePromise ?
|
|
653
|
-
obj.__handle(list.__packed, handler, onerror)
|
|
654
|
-
: obj.__pack(list, handler, onerror) }
|
|
655
|
-
Object.defineProperty(obj, '__packed', {
|
|
656
|
-
value: list,
|
|
657
|
-
enumerable: false,
|
|
658
|
-
// NOTE: this is needed for self-resolve...
|
|
659
|
-
writable: true,
|
|
660
|
-
})
|
|
661
|
-
// handle promise state...
|
|
662
|
-
try{
|
|
663
|
-
var res = obj.__unpack(list)
|
|
664
|
-
}catch(err){
|
|
665
|
-
promise.reject(err) }
|
|
666
|
-
res instanceof Promise ?
|
|
667
|
-
res
|
|
668
|
-
.then(function(list){
|
|
669
|
-
promise.resolve(list) })
|
|
670
|
-
.catch(promise.reject)
|
|
671
|
-
: promise.resolve(res)
|
|
672
|
-
// XXX EXPEREMENTAL
|
|
673
|
-
// XXX do we handle errors here???
|
|
674
|
-
// self-resolve state...
|
|
675
|
-
list instanceof Promise ?
|
|
676
|
-
list.then(function(list){
|
|
677
|
-
obj.__packed = list })
|
|
678
|
-
: list.forEach(function(elem, i){
|
|
679
|
-
elem instanceof Promise
|
|
680
|
-
&& elem.then(function(elem){
|
|
681
|
-
lst = obj.__packed.slice()
|
|
682
|
-
lst[i] = elem
|
|
683
|
-
obj.__packed = lst }) }) }
|
|
684
|
-
return obj },
|
|
685
|
-
})
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
//---------------------------------------------------------------------
|
|
690
|
-
// XXX EXPEREMENTAL/HACK...
|
|
691
|
-
|
|
692
|
-
// XXX we are getting a list with promises triggered outside, we can't
|
|
693
|
-
// control order of execution of this but we can control in what
|
|
694
|
-
// order the handler is called...
|
|
695
|
-
// XXX this potentially shows a bug with IterablePromise:
|
|
696
|
-
// Promise.seqiter(
|
|
697
|
-
// [1, Promise.resolve(2), 3, Promise.resolve(4)],
|
|
698
|
-
// e => (console.log('---', e), e))
|
|
699
|
-
// ...this will not resolve/replace the 4's promise...
|
|
700
|
-
// for context:
|
|
701
|
-
// await Promise.resolve(Promise.resolve(Promise.resolve(123)))
|
|
702
|
-
// -> 123
|
|
703
|
-
// ...is this just a nesting issue here???
|
|
704
|
-
// Q: what IterablePromise does/should do if a promise resolves to
|
|
705
|
-
// a promise multiple times...
|
|
706
|
-
// XXX not sure if this is a viable strategy....
|
|
707
|
-
var IterableSequentialPromise =
|
|
708
|
-
module.IterableSequentialPromise =
|
|
709
|
-
object.Constructor('IterableSequentialPromise', IterablePromise, {
|
|
710
|
-
__new__: function(_, list, handler=undefined, onerror=undefined){
|
|
711
|
-
var [_, list, ...rest] = arguments
|
|
712
|
-
var res = list
|
|
713
|
-
// format the list...
|
|
714
|
-
if(list instanceof Array
|
|
715
|
-
|| list instanceof Promise){
|
|
716
|
-
|
|
717
|
-
var pre_process = function(list, start=0){
|
|
718
|
-
if(list instanceof Promise){
|
|
719
|
-
return list.then(pre_process) }
|
|
720
|
-
res = []
|
|
721
|
-
for(let [i, e] of list.entries().slice(start)){
|
|
722
|
-
if(e instanceof Promise){
|
|
723
|
-
res.push(e.then(function(e){
|
|
724
|
-
return [e,
|
|
725
|
-
// XXX need to flatten this...
|
|
726
|
-
...pre_process(list, i+1)] }))
|
|
727
|
-
break }
|
|
728
|
-
res.push(e) }
|
|
729
|
-
return res }
|
|
730
|
-
|
|
731
|
-
res = pre_process(list)
|
|
732
|
-
|
|
733
|
-
var obj = IterablePromise.prototype.__new__.call(this, _, res, 'raw')
|
|
734
|
-
|
|
735
|
-
return obj
|
|
736
|
-
}
|
|
737
|
-
// XXX use .parentCall(..)...
|
|
738
|
-
return IterablePromise.prototype.__new__.call(this, _, res, ...rest) },
|
|
739
|
-
})
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
//---------------------------------------------------------------------
|
|
744
|
-
// Interactive promise...
|
|
745
|
-
//
|
|
746
|
-
// Adds ability to send messages to the running promise.
|
|
747
|
-
//
|
|
748
|
-
|
|
749
|
-
var InteractivePromise =
|
|
750
|
-
module.InteractivePromise =
|
|
751
|
-
object.Constructor('InteractivePromise', Promise, {
|
|
752
|
-
// XXX do we need a way to remove handlers???
|
|
753
|
-
__message_handlers: null,
|
|
754
|
-
|
|
755
|
-
send: function(...args){
|
|
756
|
-
var that = this
|
|
757
|
-
;(this.__message_handlers || [])
|
|
758
|
-
.forEach(function(h){ h.call(that, ...args) })
|
|
759
|
-
return this },
|
|
760
|
-
|
|
761
|
-
then: IterablePromise.prototype.then,
|
|
762
|
-
|
|
763
|
-
//
|
|
764
|
-
// Promise.interactive(handler)
|
|
765
|
-
// -> interacive-promise
|
|
766
|
-
//
|
|
767
|
-
// handler(resolve, reject, onmessage)
|
|
768
|
-
//
|
|
769
|
-
// onmessage(func)
|
|
770
|
-
//
|
|
771
|
-
//
|
|
772
|
-
__new__: function(_, handler){
|
|
773
|
-
var handlers = []
|
|
774
|
-
|
|
775
|
-
var onmessage = function(func){
|
|
776
|
-
// remove all handlers...
|
|
777
|
-
if(func === false){
|
|
778
|
-
var h = (obj == null ?
|
|
779
|
-
handlers
|
|
780
|
-
: (obj.__message_handlers || []))
|
|
781
|
-
h.splice(0, handlers.length)
|
|
782
|
-
// remove a specific handler...
|
|
783
|
-
} else if(arguments[1] === false){
|
|
784
|
-
var h = (obj == null ?
|
|
785
|
-
handlers
|
|
786
|
-
: (obj.__message_handlers || []))
|
|
787
|
-
h.splice(h.indexOf(func), 1)
|
|
788
|
-
// register a handler...
|
|
789
|
-
} else {
|
|
790
|
-
var h = obj == null ?
|
|
791
|
-
// NOTE: we need to get the handlers from
|
|
792
|
-
// .__message_handlers unless we are not
|
|
793
|
-
// fully defined yet, then use the bootstrap
|
|
794
|
-
// container (handlers)...
|
|
795
|
-
// ...since we can call onmessage(..) while
|
|
796
|
-
// the promise is still defined there is no
|
|
797
|
-
// way to .send(..) until it returns a promise
|
|
798
|
-
// object, this races here are highly unlikely...
|
|
799
|
-
handlers
|
|
800
|
-
: (obj.__message_handlers =
|
|
801
|
-
obj.__message_handlers ?? [])
|
|
802
|
-
handlers.push(func) } }
|
|
803
|
-
|
|
804
|
-
var obj = Reflect.construct(
|
|
805
|
-
InteractivePromise.__proto__,
|
|
806
|
-
!handler ?
|
|
807
|
-
[]
|
|
808
|
-
: [function(resolve, reject){
|
|
809
|
-
return handler(resolve, reject, onmessage) }],
|
|
810
|
-
InteractivePromise)
|
|
811
|
-
Object.defineProperty(obj, '__message_handlers', {
|
|
812
|
-
value: handlers,
|
|
813
|
-
enumerable: false,
|
|
814
|
-
// XXX should this be .configurable???
|
|
815
|
-
configurable: true,
|
|
816
|
-
})
|
|
817
|
-
return obj },
|
|
818
|
-
})
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
//---------------------------------------------------------------------
|
|
823
|
-
// Cooperative promise...
|
|
824
|
-
//
|
|
825
|
-
// A promise that can be resolved/rejected externally.
|
|
826
|
-
//
|
|
827
|
-
// NOTE: normally this has no internal resolver logic...
|
|
828
|
-
//
|
|
829
|
-
|
|
830
|
-
var CooperativePromise =
|
|
831
|
-
module.CooperativePromise =
|
|
832
|
-
object.Constructor('CooperativePromise', Promise, {
|
|
833
|
-
__handlers: null,
|
|
834
|
-
|
|
835
|
-
get isSet(){
|
|
836
|
-
return this.__handlers === false },
|
|
837
|
-
|
|
838
|
-
set: function(value, resolve=true){
|
|
839
|
-
// can't set twice...
|
|
840
|
-
if(this.isSet){
|
|
841
|
-
throw new Error('.set(..): can not set twice') }
|
|
842
|
-
// bind to promise...
|
|
843
|
-
if(value && value.then && value.catch){
|
|
844
|
-
value.then(handlers.resolve)
|
|
845
|
-
value.catch(handlers.reject)
|
|
846
|
-
// resolve with value...
|
|
847
|
-
} else {
|
|
848
|
-
resolve ?
|
|
849
|
-
this.__handlers.resolve(value)
|
|
850
|
-
: this.__handlers.reject(value) }
|
|
851
|
-
// cleanup and prevent setting twice...
|
|
852
|
-
this.__handlers = false
|
|
853
|
-
return this },
|
|
854
|
-
|
|
855
|
-
then: IterablePromise.prototype.then,
|
|
856
|
-
|
|
857
|
-
__new__: function(){
|
|
858
|
-
var handlers
|
|
859
|
-
var resolver = arguments[1]
|
|
860
|
-
|
|
861
|
-
var obj = Reflect.construct(
|
|
862
|
-
CooperativePromise.__proto__,
|
|
863
|
-
[function(resolve, reject){
|
|
864
|
-
handlers = {resolve, reject}
|
|
865
|
-
// NOTE: this is here to support builtin .then(..)
|
|
866
|
-
resolver
|
|
867
|
-
&& resolver(resolve, reject) }],
|
|
868
|
-
CooperativePromise)
|
|
869
|
-
|
|
870
|
-
Object.defineProperty(obj, '__handlers', {
|
|
871
|
-
value: handlers,
|
|
872
|
-
enumerable: false,
|
|
873
|
-
writable: true,
|
|
874
|
-
})
|
|
875
|
-
return obj },
|
|
876
|
-
})
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
//---------------------------------------------------------------------
|
|
881
|
-
|
|
882
|
-
// XXX EXPEREMENTAL...
|
|
883
|
-
var ProxyPromise =
|
|
884
|
-
module.ProxyPromise =
|
|
885
|
-
object.Constructor('ProxyPromise', Promise, {
|
|
886
|
-
|
|
887
|
-
then: IterablePromise.prototype.then,
|
|
888
|
-
|
|
889
|
-
__new__: function(context, other, nooverride=false){
|
|
890
|
-
var proto = 'prototype' in other ?
|
|
891
|
-
other.prototype
|
|
892
|
-
: other
|
|
893
|
-
var obj = Reflect.construct(
|
|
894
|
-
ProxyPromise.__proto__,
|
|
895
|
-
[function(resolve, reject){
|
|
896
|
-
context.then(resolve)
|
|
897
|
-
context.catch(reject) }],
|
|
898
|
-
ProxyPromise)
|
|
899
|
-
// populate...
|
|
900
|
-
// NOTE: we are not using object.deepKeys(..) here as we need
|
|
901
|
-
// the key origin not to trigger property getters...
|
|
902
|
-
var seen = new Set()
|
|
903
|
-
nooverride = nooverride instanceof Array ?
|
|
904
|
-
new Set(nooverride)
|
|
905
|
-
: nooverride
|
|
906
|
-
while(proto != null){
|
|
907
|
-
Object.entries(Object.getOwnPropertyDescriptors(proto))
|
|
908
|
-
.forEach(function([key, value]){
|
|
909
|
-
// skip overloaded keys...
|
|
910
|
-
if(seen.has(key)){
|
|
911
|
-
return }
|
|
912
|
-
// skip non-functions...
|
|
913
|
-
if(typeof(value.value) != 'function'){
|
|
914
|
-
return }
|
|
915
|
-
// skip non-enumerable except for Object.prototype.run(..)...
|
|
916
|
-
if(!(key == 'run'
|
|
917
|
-
&& Object.prototype.run === value.value)
|
|
918
|
-
&& !value.enumerable){
|
|
919
|
-
return }
|
|
920
|
-
// do not override existing methods...
|
|
921
|
-
if(nooverride === true ?
|
|
922
|
-
key in obj
|
|
923
|
-
: nooverride instanceof Set ?
|
|
924
|
-
nooverride.has(key)
|
|
925
|
-
: nooverride){
|
|
926
|
-
return }
|
|
927
|
-
// proxy...
|
|
928
|
-
obj[key] = promiseProxy(key) })
|
|
929
|
-
proto = proto.__proto__ }
|
|
930
|
-
return obj },
|
|
931
|
-
})
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
//---------------------------------------------------------------------
|
|
936
|
-
|
|
937
|
-
// XXX should this support async generators???
|
|
938
|
-
var syncAllProxy =
|
|
939
|
-
function(name){
|
|
940
|
-
return function(lst){
|
|
941
|
-
var sync = true
|
|
942
|
-
for(var e of lst){
|
|
943
|
-
if(e instanceof Promise
|
|
944
|
-
&& !(e instanceof SyncPromise)){
|
|
945
|
-
sync = false
|
|
946
|
-
break } }
|
|
947
|
-
return sync ?
|
|
948
|
-
this.resolve(lst)
|
|
949
|
-
: Promise[name](lst) } }
|
|
950
|
-
|
|
951
|
-
// XXX REVISE/TEST...
|
|
952
|
-
// XXX should this support async generators???
|
|
953
|
-
var syncAnyProxy =
|
|
954
|
-
function(name){
|
|
955
|
-
return function(lst){
|
|
956
|
-
for(var e of lst){
|
|
957
|
-
if(e instanceof SyncPromise
|
|
958
|
-
&& !('error' in e)){
|
|
959
|
-
return e }
|
|
960
|
-
if(!(e instanceof Promise)){
|
|
961
|
-
return this.resolve(e) } }
|
|
962
|
-
return Promise[name](list) } }
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
966
|
-
|
|
967
|
-
// XXX EXPEREMENTAL...
|
|
968
|
-
// XXX DOCS...
|
|
969
|
-
// XXX like promise but if a value can be generated sync then this will
|
|
970
|
-
// run in sync otherwise it will fall back to being a promise...
|
|
971
|
-
// XXX should we throw errors in sync mode??? ...option???
|
|
972
|
-
var SyncPromise =
|
|
973
|
-
module.SyncPromise =
|
|
974
|
-
object.Constructor('SyncPromise', Promise, {
|
|
975
|
-
// NOTE: we need to overload these as the builtin versions sneak-in
|
|
976
|
-
// async-ness before we can catch it in .__new__(..)
|
|
977
|
-
resolve: function(value){
|
|
978
|
-
return new this(function(resolve){ resolve(value) }) },
|
|
979
|
-
reject: function(error){
|
|
980
|
-
return new this(function(_, reject){ reject(error) }) },
|
|
981
|
-
// NOTE: these essentially add a special case where the inputs are
|
|
982
|
-
// either not promises or SyncPromise instances...
|
|
983
|
-
all: syncAllProxy('all'),
|
|
984
|
-
allSettled: syncAllProxy('allSettled'),
|
|
985
|
-
any: syncAnyProxy('any'),
|
|
986
|
-
race: syncAnyProxy('race'),
|
|
987
|
-
},{
|
|
988
|
-
//value: undefined,
|
|
989
|
-
//error: undefined,
|
|
990
|
-
|
|
991
|
-
// NOTE: if this is called it means that .__new__(..) returned in sync
|
|
992
|
-
// mode and thus set .value and possibly .error, soe there is no
|
|
993
|
-
// need to check for .value...
|
|
994
|
-
then: function(resolve, reject){
|
|
995
|
-
return this.hasOwnProperty('error') ?
|
|
996
|
-
this.constructor.reject(
|
|
997
|
-
reject ?
|
|
998
|
-
reject(this.error)
|
|
999
|
-
: this.error)
|
|
1000
|
-
: resolve ?
|
|
1001
|
-
this.constructor.resolve(
|
|
1002
|
-
resolve(this.value))
|
|
1003
|
-
// XXX should we return a copy???
|
|
1004
|
-
: this },
|
|
1005
|
-
sync: function(error='throw'){
|
|
1006
|
-
if(error !== false
|
|
1007
|
-
&& 'error' in this){
|
|
1008
|
-
if(typeof(error) != 'function'){
|
|
1009
|
-
throw this.error }
|
|
1010
|
-
return error(this.error) }
|
|
1011
|
-
return this.value },
|
|
1012
|
-
|
|
1013
|
-
// NOTE: if func calls resolve(..) with a promise then this will return
|
|
1014
|
-
// that promise...
|
|
1015
|
-
__new__: function(context, func){
|
|
1016
|
-
var value
|
|
1017
|
-
var resolve = function(res){
|
|
1018
|
-
return (value = res) }
|
|
1019
|
-
var rejected
|
|
1020
|
-
var error
|
|
1021
|
-
var reject = function(err){
|
|
1022
|
-
rejected = true
|
|
1023
|
-
return (error = err) }
|
|
1024
|
-
// call...
|
|
1025
|
-
try{
|
|
1026
|
-
func(resolve, reject)
|
|
1027
|
-
}catch(err){
|
|
1028
|
-
reject(err) }
|
|
1029
|
-
// async...
|
|
1030
|
-
if(!error
|
|
1031
|
-
&& value instanceof Promise){
|
|
1032
|
-
return object.ASIS(value) }
|
|
1033
|
-
// sync...
|
|
1034
|
-
var obj = Promise.resolve(value)
|
|
1035
|
-
obj.value = value
|
|
1036
|
-
rejected
|
|
1037
|
-
&& (obj.error = error)
|
|
1038
|
-
return obj },
|
|
1039
|
-
})
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
//---------------------------------------------------------------------
|
|
1044
|
-
|
|
1045
|
-
var PromiseMixin =
|
|
1046
|
-
module.PromiseMixin =
|
|
1047
|
-
object.Mixin('PromiseMixin', 'soft', {
|
|
1048
|
-
iter: IterablePromise,
|
|
1049
|
-
// XXX
|
|
1050
|
-
seqiter: IterableSequentialPromise,
|
|
1051
|
-
|
|
1052
|
-
interactive: InteractivePromise,
|
|
1053
|
-
cooperative: CooperativePromise,
|
|
1054
|
-
|
|
1055
|
-
sync: SyncPromise,
|
|
1056
|
-
|
|
1057
|
-
// XXX should this be implemented via SyncPromise???
|
|
1058
|
-
// XXX not sure if we need to expand async generators...
|
|
1059
|
-
// (update README if this changes)
|
|
1060
|
-
awaitOrRun: function(data, func, error){
|
|
1061
|
-
data = [...arguments]
|
|
1062
|
-
func = data.pop()
|
|
1063
|
-
if(typeof(data.at(-1)) == 'function'){
|
|
1064
|
-
error = func
|
|
1065
|
-
func = data.pop() }
|
|
1066
|
-
error = error ?
|
|
1067
|
-
[error]
|
|
1068
|
-
: []
|
|
1069
|
-
// check if we need to await...
|
|
1070
|
-
return data.reduce(function(res, e){
|
|
1071
|
-
return res
|
|
1072
|
-
|| e instanceof Promise }, false) ?
|
|
1073
|
-
// NOTE: we will not reach this on empty data...
|
|
1074
|
-
(data.length > 1 ?
|
|
1075
|
-
Promise.all(data)
|
|
1076
|
-
.then(
|
|
1077
|
-
function(res){
|
|
1078
|
-
return func(...res) },
|
|
1079
|
-
...error)
|
|
1080
|
-
: data[0].then(func, ...error))
|
|
1081
|
-
// XXX not sure if we need to expand async generators...
|
|
1082
|
-
// ...since it has .then(..) it can be treated as a promise...
|
|
1083
|
-
// XXX should we just check for .then(..) ???
|
|
1084
|
-
// XXX update README if this changes...
|
|
1085
|
-
: (data.length == 1
|
|
1086
|
-
&& Symbol.asyncIterator in data[0]
|
|
1087
|
-
&& 'then' in data[0]) ?
|
|
1088
|
-
data[0].then(func, ...error)
|
|
1089
|
-
: error.length > 0 ?
|
|
1090
|
-
function(){
|
|
1091
|
-
try{
|
|
1092
|
-
return func(...data)
|
|
1093
|
-
}catch(err){
|
|
1094
|
-
return error[0](err) } }()
|
|
1095
|
-
: func(...data) },
|
|
1096
|
-
})
|
|
1097
|
-
|
|
1098
|
-
PromiseMixin(Promise)
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
var PromiseProtoMixin =
|
|
1102
|
-
module.PromiseProtoMixin =
|
|
1103
|
-
object.Mixin('PromiseProtoMixin', 'soft', {
|
|
1104
|
-
as: ProxyPromise,
|
|
1105
|
-
|
|
1106
|
-
iter: function(handler=undefined, onerror=undefined){
|
|
1107
|
-
return IterablePromise(this, handler, onerror) },
|
|
1108
|
-
// XXX
|
|
1109
|
-
seqiter: function(handler=undefined, onerror=undefined){
|
|
1110
|
-
return IterableSequentialPromise(this, handler, onerror) },
|
|
1111
|
-
|
|
1112
|
-
// unify the general promise API with other promise types...
|
|
1113
|
-
// XXX should this be here???
|
|
1114
|
-
// XXX error if given must return the result... (???)
|
|
1115
|
-
sync: function(error){
|
|
1116
|
-
typeof(error) == 'function'
|
|
1117
|
-
&& this.catch(error)
|
|
1118
|
-
return this },
|
|
1119
|
-
})
|
|
1120
|
-
|
|
1121
|
-
PromiseProtoMixin(Promise.prototype)
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
/**********************************************************************
|
|
1127
|
-
* vim:set ts=4 sw=4 nowrap : */ return module })
|