ig-types 6.10.1 → 6.11.2

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 CHANGED
@@ -492,6 +492,7 @@ object.Mixin('ArrayProtoMixin', 'soft', {
492
492
  smap: stoppableList('map'),
493
493
  sfilter: stoppableList('filter'),
494
494
  sreduce: stoppableValue('reduce'),
495
+ sreduceRight: stoppableValue('reduceRight'),
495
496
  sforEach: stoppableValue('map', true),
496
497
 
497
498
  // Chunk iteration...
package/Promise.js CHANGED
@@ -80,12 +80,13 @@ object.Constructor('IterablePromise', Promise, {
80
80
  // NOTE: these are different to Array's equivalents in that the handler
81
81
  // is called not in the order of the elements but rather in order
82
82
  // of promise resolution...
83
- // NOTE: index of items is unknowable because items can expand on
83
+ // NOTE: index of items is unknowable because items can expand and
84
84
  // contract depending on handlrs (e.g. .filter(..) can remove
85
85
  // items)...
86
86
  // This the following can not be implemented here:
87
87
  // .slice(..)
88
88
  // .splice(..)
89
+ // .values() / .keys()
89
90
  // .at(..)
90
91
  // [Symbol.iterator]() - needs to be sync...
91
92
  // The followng methods are questionable:
@@ -93,36 +94,65 @@ object.Constructor('IterablePromise', Promise, {
93
94
  // .includes(..)
94
95
  // .some(..) / .every(..)
95
96
  // .sort(..)
97
+ //
96
98
  // XXX should these support STOP???
97
99
  map: function(func){
98
- return this.constructor(this.__list,
100
+ return this.constructor(this,
99
101
  function(e){
100
102
  return [func(e)] }) },
101
103
  filter: function(func){
102
- return this.constructor(this.__list,
104
+ return this.constructor(this,
103
105
  function(e){
104
106
  return func(e) ?
105
107
  [e]
106
108
  : [] }) },
109
+ // NOTE: this does not return an iterable promise as we can't know
110
+ // what the user reduces to...
111
+ // XXX we could look at the initial state though...
112
+ // NOTE: the items can be handled out of order because the nested
113
+ // promises can resolve in any order.
114
+ // XXX write how to go around this...
115
+ // NOTE: since order of execution can not be guaranteed there is no
116
+ // point in implementing .reduceRight(..)
107
117
  reduce: function(func, res){
108
- return this.constructor(this.__list,
118
+ return this.constructor(this,
109
119
  function(e){
110
120
  res = func(res, e)
111
121
  return [] })
112
122
  .then(function(){
113
123
  return res }) },
114
124
  flat: function(depth=1){
115
- return this.constructor(this.__list,
125
+ return this.constructor(this,
116
126
  function(e){
117
- return (e && e.flat) ?
118
- e.flat(depth)
119
- : e }) },
120
- // XXX do we need this???
121
- //iter: function(){
122
- // return this },
123
-
124
-
125
- // XXX do we need:
127
+ return (depth > 1
128
+ && e != null
129
+ && e.flat) ?
130
+ e.flat(depth-1)
131
+ : depth != 0 ?
132
+ e
133
+ : [e] }) },
134
+ reverse: function(){
135
+ var lst = this.__list
136
+ return this.constructor(
137
+ lst instanceof Promise ?
138
+ lst.then(function(elems){
139
+ return elems instanceof Array ?
140
+ elems.slice()
141
+ .reverse()
142
+ : elems })
143
+ : lst
144
+ .map(function(elems){
145
+ return elems instanceof Array ?
146
+ elems.slice()
147
+ .reverse()
148
+ : elems instanceof Promise ?
149
+ elems.then(function(elems){
150
+ return elems.reverse() })
151
+ : elems })
152
+ .reverse(),
153
+ 'raw') },
154
+
155
+ // XXX do we need these?
126
156
  // .pop()
127
157
  // .shift()
128
158
  // .first() / .last()
@@ -182,8 +212,8 @@ object.Constructor('IterablePromise', Promise, {
182
212
  //
183
213
  // Spectial cases usefull for extending this constructor...
184
214
  //
185
- // Clone the iterator...
186
- // Promise.iter([ .. ], false)
215
+ // Set raw .__list without any pre-processing...
216
+ // Promise.iter([ .. ], 'raw')
187
217
  // -> iterable-promise
188
218
  //
189
219
  // Create a rejected iterator...
@@ -204,9 +234,8 @@ object.Constructor('IterablePromise', Promise, {
204
234
  // - another issue here is that the stop would happen in order of
205
235
  // execution and not order of elements...
206
236
  __new__: function(_, list, handler){
207
- var promise
208
-
209
237
  // instance...
238
+ var promise
210
239
  var obj = Reflect.construct(
211
240
  IterablePromise.__proto__,
212
241
  [function(resolve, reject){
@@ -220,49 +249,47 @@ object.Constructor('IterablePromise', Promise, {
220
249
  IterablePromise)
221
250
 
222
251
  if(promise){
223
- //var __stop = false
224
- // apply handler(..) to the list...
225
- //
226
- // NOTE: the top level promises are not wrapped in arrays...
227
- list =
228
- // apply the handler...
229
- handler ?
230
- // XXX can we handle STOP here???
231
- // ...we will not be able to stop already started
232
- // promises...
233
- list.map(function(block){
234
- //* XXX STOP...
235
- return (block instanceof Array ?
236
- block
237
- : [block])
238
- /*/
239
- // NOTE: we are not using Array's .iter() so as to
240
- // keep the dependency minimal...
241
- return generator.iter(
242
- block instanceof Array ?
243
- block
244
- : [block])
245
- //*/
246
- .map(function(e){
247
- // NOTE: we are counting actual expanded
248
- // values and not the "blocks"...
249
- return (e && e.then && e.catch) ?
250
- // promise...
251
- e.then(function(v){
252
- return handler(v) })
253
- // basic value...
254
- : handler(e) }) })
255
- .flat()
256
- // XXX STOP
257
- //.toArray()
258
- // normal constructor...
259
- : handler === undefined ?
260
- list.map(function(e){
261
- return e instanceof Promise ?
262
- e
263
- : [e] })
264
- // clone...
265
- : list.slice()
252
+
253
+ if(handler != 'raw'){
254
+ handler = handler
255
+ ?? function(e){
256
+ return [e] }
257
+
258
+ // NOTE: this is recursive to handle expanding nested promises...
259
+ var handle = function(elem){
260
+ // call the handler...
261
+ return (elem && elem.then) ?
262
+ //elem.then(function(elem){
263
+ // return handler(elem) })
264
+ elem.then(handler)
265
+ : handler(elem) }
266
+
267
+ // handle the list...
268
+ // NOTE: we can't .flat() the results here as we need to
269
+ // wait till all the promises resolve...
270
+ list =
271
+ (list instanceof IterablePromise
272
+ && !(list.__list instanceof Promise)) ?
273
+ // NOTE: this is essentially the same as below but
274
+ // with a normalized list as input...
275
+ // XXX can we merge the two???
276
+ list.__list
277
+ .map(function(elems){
278
+ return elems instanceof Promise ?
279
+ elems.then(function(elems){
280
+ return elems
281
+ .map(handle)
282
+ .flat() })
283
+ : elems
284
+ .map(handle)
285
+ .flat() })
286
+ : list instanceof Promise ?
287
+ // special case: promised list...
288
+ list.then(function(list){
289
+ return [list].flat()
290
+ .map(handle) })
291
+ : [list].flat()
292
+ .map(handle) }
266
293
 
267
294
  Object.defineProperty(obj, '__list', {
268
295
  value: list,
@@ -270,9 +297,14 @@ object.Constructor('IterablePromise', Promise, {
270
297
  })
271
298
 
272
299
  // handle promise state...
273
- Promise.all(list)
300
+ ;(list instanceof Promise ?
301
+ // special case: promised list...
302
+ list
303
+ : Promise.all([list].flat()))
274
304
  .then(function(res){
275
- promise.resolve(res.flat()) })
305
+ promise.resolve(handler ?
306
+ res.flat()
307
+ : res) })
276
308
  .catch(promise.reject) }
277
309
 
278
310
  return obj },
@@ -415,6 +447,51 @@ object.Constructor('CooperativePromise', Promise, {
415
447
 
416
448
 
417
449
 
450
+ //---------------------------------------------------------------------
451
+
452
+ // XXX EXPEREMENTAL...
453
+ var ProxyPromise =
454
+ module.ProxyPromise =
455
+ object.Constructor('ProxyPromise', Promise, {
456
+ __new__: function(context, constructor){
457
+ var proto = 'prototype' in constructor ?
458
+ constructor.prototype
459
+ : constructor
460
+ var obj = Reflect.construct(
461
+ ProxyPromise.__proto__,
462
+ [function(resolve, reject){
463
+ context.then(resolve)
464
+ context.catch(reject) }],
465
+ ProxyPromise)
466
+ // populate...
467
+ // NOTE: we are not using object.deepKeys(..) here as we need
468
+ // the key origin not to trigger property getters...
469
+ var seen = new Set()
470
+ while(proto != null){
471
+ Object.entries(Object.getOwnPropertyDescriptors(proto))
472
+ .forEach(function([key, value]){
473
+ // skip overloaded keys...
474
+ if(seen.has(key)){
475
+ return }
476
+ // skip non-functions...
477
+ if(typeof(value.value) != 'function'){
478
+ return }
479
+ // skip non-enumerable except for Object.prototype.run(..)...
480
+ if(!(key == 'run'
481
+ && Object.prototype.run === value.value)
482
+ && !value.enumerable){
483
+ return }
484
+ // proxy...
485
+ obj[key] = function(...args){
486
+ // XXX should we also .catch(..) here???
487
+ return context.then(function(res){
488
+ return res[key](...args) }) } })
489
+ proto = proto.__proto__ }
490
+ return obj },
491
+ })
492
+
493
+
494
+
418
495
  //---------------------------------------------------------------------
419
496
 
420
497
  var PromiseMixin =
@@ -425,10 +502,23 @@ object.Mixin('PromiseMixin', 'soft', {
425
502
  cooperative: CooperativePromise,
426
503
  })
427
504
 
428
-
429
505
  PromiseMixin(Promise)
430
506
 
431
507
 
508
+ // XXX EXPEREMENTAL...
509
+ var PromiseProtoMixin =
510
+ module.PromiseProtoMixin =
511
+ object.Mixin('PromiseProtoMixin', 'soft', {
512
+ as: ProxyPromise,
513
+
514
+ // XXX
515
+ iter: function(){
516
+ return IterablePromise(this) },
517
+ })
518
+
519
+ PromiseProtoMixin(Promise.prototype)
520
+
521
+
432
522
 
433
523
 
434
524
  /**********************************************************************
package/Promise.js.bak ADDED
@@ -0,0 +1,548 @@
1
+ /**********************************************************************
2
+ *
3
+ *
4
+ *
5
+ *
6
+ * This defines the following extensions to Promise:
7
+ *
8
+ * Promise.iter(seq)
9
+ * Iterable promise object.
10
+ * Similar to Promise.all(..) but adds basic iterator/generator
11
+ * API and will resolve the items as they are ready (resolved).
12
+ *
13
+ * Promise.interactive(handler)
14
+ * Interactive promise object.
15
+ * This adds a basic message passing API to the promise.
16
+ *
17
+ * Promise.cooperative()
18
+ * Cooperative promise object.
19
+ * Exposes the API to resolve/reject the promise object
20
+ * externally.
21
+ *
22
+ *
23
+ *
24
+ **********************************************/ /* c8 ignore next 2 */
25
+ ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
26
+ (function(require){ var module={} // make module AMD/node compatible...
27
+ /*********************************************************************/
28
+
29
+ var object = require('ig-object')
30
+
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
+
44
+
45
+ //---------------------------------------------------------------------
46
+ // Iterable promise...
47
+ //
48
+ // Like Promise.all(..) but adds ability to iterate through results
49
+ // via generators .map(..)/.reduce(..) and friends...
50
+ //
51
+
52
+ var IterablePromise =
53
+ module.IterablePromise =
54
+ object.Constructor('IterablePromise', Promise, {
55
+ // XXX
56
+ //STOP: object.STOP,
57
+
58
+ //
59
+ // Format:
60
+ // [
61
+ // [ <value> ],
62
+ // <promise>,
63
+ // ...
64
+ // ]
65
+ //
66
+ __list: null,
67
+
68
+
69
+ // iterator methods...
70
+ //
71
+ // These will return a new IterablePromise instance...
72
+ //
73
+ // When called from a resolved promise these will return a new
74
+ // resolved promise with updated values...
75
+ //
76
+ // When called from a rejected promise these will return a rejected
77
+ // with the same reason promise...
78
+ //
79
+ //
80
+ // NOTE: these are different to Array's equivalents in that the handler
81
+ // is called not in the order of the elements but rather in order
82
+ // of promise resolution...
83
+ // NOTE: index of items is unknowable because items can expand and
84
+ // contract depending on handlrs (e.g. .filter(..) can remove
85
+ // items)...
86
+ // This the following can not be implemented here:
87
+ // .slice(..)
88
+ // .splice(..)
89
+ // .values() / .keys()
90
+ // .at(..)
91
+ // [Symbol.iterator]() - needs to be sync...
92
+ // The followng methods are questionable:
93
+ // .indexOf(..)
94
+ // .includes(..)
95
+ // .some(..) / .every(..)
96
+ // .sort(..)
97
+ // XXX BUG:
98
+ // Promise.iter([1,2,3])
99
+ // .map(e => e)
100
+ // is not the same as:
101
+ // Promise.iter([1,2,3])
102
+ // .map(e => e)
103
+ // .map(e => e)
104
+ // XXX should these support STOP???
105
+ map: function(func){
106
+ return this.constructor(this.__list.flat(),
107
+ function(e){
108
+ return [func(e)] }) },
109
+ filter: function(func){
110
+ return this.constructor(this.__list.flat(),
111
+ function(e){
112
+ return func(e) ?
113
+ [e]
114
+ : [] }) },
115
+ // NOTE: this does not return an iterable promise as we can't know
116
+ // what the user reduces to...
117
+ // NOTE: the items can be handled out of order because the nested
118
+ // promises can resolve in any order.
119
+ // XXX write how to go around this...
120
+ // NOTE: since order of execution can not be guaranteed there is no
121
+ // point in implementing .reduceRight(..)
122
+ reduce: function(func, res){
123
+ return this.constructor(this.__list.flat(),
124
+ function(e){
125
+ res = func(res, e)
126
+ return [] })
127
+ .then(function(){
128
+ return res }) },
129
+ flat: function(depth=1){
130
+ return this.constructor(this.__list.flat(),
131
+ function(e){
132
+ return (depth > 1
133
+ && e != null
134
+ && e.flat) ?
135
+ e.flat(depth-1)
136
+ : depth != 0 ?
137
+ e
138
+ : [e] }) },
139
+ // XXX REVERSE...
140
+ // XXX BUG:
141
+ // await Promise.iter([1, Promise.iter(['a', ['b', 'c']]), [2, 3], 4])
142
+ // .flat()
143
+ // -> [ 1, 'a', [ 'b', 'c' ], 2, 3, 4 ]
144
+ // await Promise.iter([1, Promise.iter(['a', ['b', 'c']]), [2, 3], 4])
145
+ // .flat()
146
+ // .reverse()
147
+ // -> [ 4, 2, 3, [ 'b', 'c', 'a' ], 1 ]
148
+ // ...should be:
149
+ // -> [ 4, 2, 3, [ 'b', 'c' ], 'a', 1 ]
150
+ // it's odd we are not seeing this in other places...
151
+ reverse: function(){
152
+ return this.constructor(this.__list
153
+ .map(function(elems){
154
+ return elems && elems.then ?
155
+ elems.then(function(res){
156
+ return res
157
+ .reverse()
158
+ .flat() })
159
+ : elems })
160
+ .reverse()
161
+ .flat()) },
162
+
163
+ // compatibility with root promise...
164
+ // XXX BUG:
165
+ // await Promise.iter(Promise.resolve([1,2,[3, 4]])).iter()
166
+ // -> [ [ 1, 2, 3, 4 ] ]
167
+ iter: function(){
168
+ return this.constructor(
169
+ // clone and unwrap the .__list
170
+ this.__list
171
+ .map(function(elems){
172
+ return elems && elems.then ?
173
+ elems.then(function(res){
174
+ return res instanceof Array ?
175
+ res.flat()
176
+ : res })
177
+ : elems })
178
+ .flat()) },
179
+
180
+ // XXX do we need these?
181
+ // .pop()
182
+ // .shift()
183
+ // .first() / .last()
184
+ // XXX these can change the "resolved" state...
185
+ // ...i.e. return a pending promise when called from a fulfilled
186
+ // promise....
187
+ // .concat(..)
188
+ // .push(..)
189
+ // .unshift(..)
190
+ // .first(..) / .last(..)
191
+
192
+
193
+ // Overload .then(..), .catch(..) and .finally(..) to return a plain
194
+ // Promise instnace...
195
+ //
196
+ // NOTE: .catch(..) and .finally(..) are implemented through .then(..)
197
+ // so we do not need to overload those...
198
+ // NOTE: this is slightly different from .then(..) in that it can be
199
+ // called without arguments and return a promise wrapper. This can
200
+ // be useful to hide special promise functionality...
201
+ then: function (onfulfilled, onrejected){
202
+ var p = new Promise(
203
+ function(resolve, reject){
204
+ Promise.prototype.then.call(this,
205
+ // NOTE: resolve(..) / reject(..) return undefined so
206
+ // we can't pass them directly here...
207
+ function(res){
208
+ resolve(res)
209
+ return res },
210
+ function(res){
211
+ reject(res)
212
+ return res }) }.bind(this))
213
+ return arguments.length > 0 ?
214
+ p.then(...arguments)
215
+ : p },
216
+
217
+
218
+ //
219
+ // Promise.iter([ .. ])
220
+ // -> iterable-promise
221
+ //
222
+ // Promise.iter([ .. ], handler)
223
+ // -> iterable-promise
224
+ //
225
+ //
226
+ // handler(e)
227
+ // -> [value]
228
+ // -> []
229
+ //
230
+ //
231
+ // NOTE: element index is unknowable untill the full list is expanded
232
+ // as handler(..)'s return value can expand to any number of
233
+ // items...
234
+ // XXX we can make the index a promise, then if the client needs
235
+ // the value they can wait for it...
236
+ //
237
+ //
238
+ // Spectial cases usefull for extending this constructor...
239
+ //
240
+ // Clone the iterator...
241
+ // Promise.iter([ .. ], false)
242
+ // -> iterable-promise
243
+ //
244
+ // Create a rejected iterator...
245
+ // Promise.iter(false)
246
+ // -> iterable-promise
247
+ //
248
+ //
249
+ // XXX if list is an iterator, can we fill this async???
250
+ // XXX iterator/generator as input:
251
+ // - do we unwind here or externally?
252
+ // ...feels like with the generator external unwinding is
253
+ // needed...
254
+ // XXX would be nice to support trowing STOP...
255
+ // - this is more complicated than simply suing .smap(..) instead
256
+ // of .map(..) because the list can contain async promises...
257
+ // ...would need to wrap each .then(..) call in try-catch and
258
+ // manually handle the stop...
259
+ // - another issue here is that the stop would happen in order of
260
+ // execution and not order of elements...
261
+ // XXX add support for list as a promise....
262
+ __new__: function(_, list, handler){
263
+ // handle: IterablePromise(<list>, <mode>)
264
+ if(typeof(handler) == 'string'){
265
+ mode = handler
266
+ handler = undefined }
267
+
268
+ // instance...
269
+ var promise
270
+ var obj = Reflect.construct(
271
+ IterablePromise.__proto__,
272
+ [function(resolve, reject){
273
+ // NOTE: this is here for Promise compatibilty...
274
+ if(typeof(list) == 'function'){
275
+ return list.call(this, ...arguments) }
276
+ // initial reject...
277
+ if(list === false){
278
+ return reject() }
279
+ promise = {resolve, reject} }],
280
+ IterablePromise)
281
+
282
+ if(promise){
283
+ // clone/normalize...
284
+ list =
285
+ // special case: promised list...
286
+ list instanceof Promise ?
287
+ list.then(function(res){
288
+ return [res] })
289
+ : [list].flat()
290
+ .map(function(e){
291
+ return (e && e.then) ?
292
+ e.then(function(e){
293
+ return [e] })
294
+ : [e] })
295
+
296
+ if(handler){
297
+ // NOTE: this is recursive to handle expanding nested promises...
298
+ var handle = function(elem){
299
+ // call the handler...
300
+ return (elem && elem.then) ?
301
+ elem.then(function(elems){
302
+ return elems
303
+ .map(handle)
304
+ .flat() })
305
+ : elem
306
+ .map(handler)
307
+ .flat() }
308
+
309
+ // handle the list...
310
+ //list = list.map(handle) }
311
+ list =
312
+ list instanceof Promise ?
313
+ // special case: promised list...
314
+ list.then(function(list){
315
+ return list.map(handle) })
316
+ : list.map(handle) }
317
+
318
+ Object.defineProperty(obj, '__list', {
319
+ value: list,
320
+ enumerable: false,
321
+ })
322
+
323
+ // handle promise state...
324
+ //Promise.all(list)
325
+ ;(list instanceof Promise ?
326
+ // special case: promised list...
327
+ list
328
+ : Promise.all(list))
329
+ .then(function(res){
330
+ promise.resolve(res.flat()) })
331
+ .catch(promise.reject) }
332
+
333
+ return obj },
334
+ })
335
+
336
+
337
+
338
+ //---------------------------------------------------------------------
339
+ // Interactive promise...
340
+ //
341
+ // Adds ability to send messages to the running promise.
342
+ //
343
+
344
+ var InteractivePromise =
345
+ module.InteractivePromise =
346
+ object.Constructor('InteractivePromise', Promise, {
347
+ // XXX do we need a way to remove handlers???
348
+ __message_handlers: null,
349
+
350
+ send: function(...args){
351
+ var that = this
352
+ ;(this.__message_handlers || [])
353
+ .forEach(function(h){ h.call(that, ...args) })
354
+ return this },
355
+
356
+ then: IterablePromise.prototype.then,
357
+
358
+ //
359
+ // Promise.interactive(handler)
360
+ // -> interacive-promise
361
+ //
362
+ // handler(resolve, reject, onmessage)
363
+ //
364
+ // onmessage(func)
365
+ //
366
+ //
367
+ __new__: function(_, handler){
368
+ var handlers = []
369
+
370
+ var onmessage = function(func){
371
+ // remove all handlers...
372
+ if(func === false){
373
+ var h = (obj == null ?
374
+ handlers
375
+ : (obj.__message_handlers || []))
376
+ h.splice(0, handlers.length)
377
+ // remove a specific handler...
378
+ } else if(arguments[1] === false){
379
+ var h = (obj == null ?
380
+ handlers
381
+ : (obj.__message_handlers || []))
382
+ h.splice(h.indexOf(func), 1)
383
+ // register a handler...
384
+ } else {
385
+ var h = obj == null ?
386
+ // NOTE: we need to get the handlers from .__message_handlers
387
+ // unless we are not fully defined yet, then use the
388
+ // bootstrap container (handlers)...
389
+ // ...since we can call onmessage(..) while the promise
390
+ // is still defined there is no way to .send(..) until it
391
+ // returns a promise object, this races here are highly
392
+ // unlikely...
393
+ handlers
394
+ : (obj.__message_handlers =
395
+ obj.__message_handlers ?? [])
396
+ handlers.push(func) } }
397
+
398
+ var obj = Reflect.construct(
399
+ InteractivePromise.__proto__,
400
+ !handler ?
401
+ []
402
+ : [function(resolve, reject){
403
+ return handler(resolve, reject, onmessage) }],
404
+ InteractivePromise)
405
+ Object.defineProperty(obj, '__message_handlers', {
406
+ value: handlers,
407
+ enumerable: false,
408
+ // XXX should this be .configurable???
409
+ configurable: true,
410
+ })
411
+ return obj },
412
+ })
413
+
414
+
415
+
416
+ //---------------------------------------------------------------------
417
+ // Cooperative promise...
418
+ //
419
+ // A promise that can be resolved/rejected externally.
420
+ // NOTE: normally this has no internal resolver logic...
421
+ //
422
+
423
+ var CooperativePromise =
424
+ module.CooperativePromise =
425
+ object.Constructor('CooperativePromise', Promise, {
426
+ __handlers: null,
427
+
428
+ get isSet(){
429
+ return this.__handlers === false },
430
+
431
+ set: function(value, resolve=true){
432
+ // can't set twice...
433
+ if(this.isSet){
434
+ throw new Error('.set(..): can not set twice') }
435
+ // bind to promise...
436
+ if(value && value.then && value.catch){
437
+ value.then(handlers.resolve)
438
+ value.catch(handlers.reject)
439
+ // resolve with value...
440
+ } else {
441
+ resolve ?
442
+ this.__handlers.resolve(value)
443
+ : this.__handlers.reject(value) }
444
+ // cleanup and prevent setting twice...
445
+ this.__handlers = false
446
+ return this },
447
+
448
+ then: IterablePromise.prototype.then,
449
+
450
+ __new__: function(){
451
+ var handlers
452
+ var resolver = arguments[1]
453
+
454
+ var obj = Reflect.construct(
455
+ CooperativePromise.__proto__,
456
+ [function(resolve, reject){
457
+ handlers = {resolve, reject}
458
+ // NOTE: this is here to support builtin .then(..)
459
+ resolver
460
+ && resolver(resolve, reject) }],
461
+ CooperativePromise)
462
+
463
+ Object.defineProperty(obj, '__handlers', {
464
+ value: handlers,
465
+ enumerable: false,
466
+ writable: true,
467
+ })
468
+ return obj },
469
+ })
470
+
471
+
472
+
473
+ //---------------------------------------------------------------------
474
+
475
+ // XXX EXPEREMENTAL...
476
+ var ProxyPromise =
477
+ module.ProxyPromise =
478
+ object.Constructor('ProxyPromise', Promise, {
479
+ __new__: function(context, constructor){
480
+ var proto = 'prototype' in constructor ?
481
+ constructor.prototype
482
+ : constructor
483
+ var obj = Reflect.construct(
484
+ ProxyPromise.__proto__,
485
+ [function(resolve, reject){
486
+ context.then(resolve)
487
+ context.catch(reject) }],
488
+ ProxyPromise)
489
+ // populate...
490
+ // NOTE: we are not using object.deepKeys(..) here as we need
491
+ // the key origin not to trigger property getters...
492
+ var seen = new Set()
493
+ while(proto != null){
494
+ Object.entries(Object.getOwnPropertyDescriptors(proto))
495
+ .forEach(function([key, value]){
496
+ // skip overloaded keys...
497
+ if(seen.has(key)){
498
+ return }
499
+ // skip non-functions...
500
+ if(typeof(value.value) != 'function'){
501
+ return }
502
+ // skip non-enumerable except for Object.prototype.run(..)...
503
+ if(!(key == 'run'
504
+ && Object.prototype.run === value.value)
505
+ && !value.enumerable){
506
+ return }
507
+ // proxy...
508
+ obj[key] = function(...args){
509
+ // XXX should we also .catch(..) here???
510
+ return context.then(function(res){
511
+ return res[key](...args) }) } })
512
+ proto = proto.__proto__ }
513
+ return obj },
514
+ })
515
+
516
+
517
+
518
+ //---------------------------------------------------------------------
519
+
520
+ var PromiseMixin =
521
+ module.PromiseMixin =
522
+ object.Mixin('PromiseMixin', 'soft', {
523
+ iter: IterablePromise,
524
+ interactive: InteractivePromise,
525
+ cooperative: CooperativePromise,
526
+ })
527
+
528
+ PromiseMixin(Promise)
529
+
530
+
531
+ // XXX EXPEREMENTAL...
532
+ var PromiseProtoMixin =
533
+ module.PromiseProtoMixin =
534
+ object.Mixin('PromiseProtoMixin', 'soft', {
535
+ as: ProxyPromise,
536
+
537
+ // XXX
538
+ iter: function(){
539
+ return IterablePromise(this) },
540
+ })
541
+
542
+ PromiseProtoMixin(Promise.prototype)
543
+
544
+
545
+
546
+
547
+ /**********************************************************************
548
+ * vim:set ts=4 sw=4 : */ return module })
package/README.md CHANGED
@@ -70,10 +70,16 @@ Library of JavaScript type extensions, types and utilities.
70
70
  - [`<promise-coop>.then(..)`](#promise-coopthen)
71
71
  - [Promise iteration](#promise-iteration)
72
72
  - [`Promise.iter(..)` / `promise.IterablePromise(..)`](#promiseiter--promiseiterablepromise)
73
+ - [`<promise>.iter()`](#promiseiter)
74
+ - [`<promise-iter>.iter()`](#promise-iteriter)
73
75
  - [`<promise-iter>.map(..)` / `<promise-iter>.filter(..)` / `<promise-iter>.reduce(..)`](#promise-itermap--promise-iterfilter--promise-iterreduce)
74
76
  - [`<promise-iter>.flat(..)`](#promise-iterflat)
77
+ - [`<promise-iter>.reverse()`](#promise-iterreverse)
75
78
  - [`<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally)
76
79
  - [Advanced handler](#advanced-handler)
80
+ - [Promise proxies](#promise-proxies)
81
+ - [`<promise>.as(..)`](#promiseas)
82
+ - [`<promise-proxy>.<method>(..)`](#promise-proxymethod)
77
83
  - [Generator extensions and utilities](#generator-extensions-and-utilities)
78
84
  - [The basics](#the-basics)
79
85
  - [`generator.Generator`](#generatorgenerator)
@@ -1449,8 +1455,8 @@ promise, and it is similar to a _generator_ in that it allows iteration over the
1449
1455
  contained values and chaining of operations but unlike `Promise.all(..)` this
1450
1456
  iteration occurs depth-first instead of breadth first.
1451
1457
 
1452
- Essentially one can think of _promise iterators_ vs. _generators_ as the former
1453
- being internally controlled and asynchronous while the later being externally
1458
+ One can think of _promise iterators_ vs. _generators_ as the former being
1459
+ internally controlled and asynchronous while the later being externally
1454
1460
  controlled and synchronous.
1455
1461
 
1456
1462
  Here is a traditional example using `Promise.all(..)`:
@@ -1512,8 +1518,32 @@ XXX should we support infinite generators as input?
1512
1518
  #### `Promise.iter(..)` / `promise.IterablePromise(..)`
1513
1519
 
1514
1520
  Create an _iterable promise_
1521
+
1515
1522
  ```bnf
1516
1523
  Promise.iter(<array>)
1524
+ Promise.iter(<promise>)
1525
+ -> <promise-iter>
1526
+ ```
1527
+
1528
+ #### `<promise>.iter()`
1529
+
1530
+ Wrap a promise in an promise iterator.
1531
+
1532
+ ```bnf
1533
+ <promise>.iter()
1534
+ -> <promise-iter>
1535
+ ```
1536
+
1537
+ If `<promise>` resolves to a non-array value it will be treated as a single
1538
+ element, otherwise the array will be iterated over.
1539
+
1540
+
1541
+ #### `<promise-iter>.iter()`
1542
+
1543
+ Return a shallow copy of the current promise iterator.
1544
+
1545
+ ```bnf
1546
+ <promise-iter>.iter()
1517
1547
  -> <promise-iter>
1518
1548
  ```
1519
1549
 
@@ -1542,7 +1572,7 @@ and [`.reduce(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe
1542
1572
 
1543
1573
  ```bnf
1544
1574
  <promise-iter>.reduce(<handler>, <state>)
1545
- -> <promise-iter>
1575
+ -> <promise>
1546
1576
 
1547
1577
  <handler>(<state>, <elem>)
1548
1578
  -> <state>
@@ -1555,6 +1585,15 @@ Note that these are different to `Array`'s equivalents in some details:
1555
1585
  this is because the index with _out-of-order_ and _depth-first_ execution the
1556
1586
  index is unknowable and the container is a promise/black-box.
1557
1587
 
1588
+ This is especially critical for `.reduce(..)` as iteration in an order different
1589
+ from the order of elements _can_ affect actual result if this is not expected.
1590
+
1591
+ `.reduce(..)` is also a bit different here in that it will return a basic
1592
+ `<promise>` object as we can't know what will it will reduce to.
1593
+
1594
+ Note that since `.reduce(..)` order can not be guaranteed there is no point
1595
+ in implementing `.reduceRigth(..)`.
1596
+
1558
1597
 
1559
1598
  #### `<promise-iter>.flat(..)`
1560
1599
 
@@ -1567,6 +1606,16 @@ Note that these are different to `Array`'s equivalents in some details:
1567
1606
  This is similar to [`<array>.flat(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) see it for more info.
1568
1607
 
1569
1608
 
1609
+ #### `<promise-iter>.reverse()`
1610
+
1611
+ ```bnf
1612
+ <promise-iter>.reverse()
1613
+ -> <promise-iter>
1614
+ ```
1615
+
1616
+ This is similar to [`<array>.reverse(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) see it for more info.
1617
+
1618
+
1570
1619
  #### `<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`
1571
1620
 
1572
1621
  An extension to
@@ -1621,6 +1670,56 @@ var p = Promise.iter(
1621
1670
  ```
1622
1671
 
1623
1672
 
1673
+ ### Promise proxies
1674
+
1675
+ _Promise proxies_ generate a set of prototype methods returning promises that when the parent promise is resolved will resolve to a specific method call.
1676
+
1677
+ Example:
1678
+ ```javascript
1679
+ var o = {
1680
+ method: function(...args){
1681
+ console.log('method:', ...args)
1682
+ },
1683
+ }
1684
+
1685
+ var p = Peomise.cooperative().as(o)
1686
+
1687
+ p.method(1, 2, 3) // returns a promise...
1688
+
1689
+ // ...
1690
+
1691
+ // resolving a promise will trigger all the proxy emthod execution, so
1692
+ // here 'method: 1, 2, 3' will get printed...
1693
+ p.set(o)
1694
+
1695
+ ```
1696
+
1697
+ #### `<promise>.as(..)`
1698
+
1699
+ Create a promise proxy
1700
+
1701
+ ```bnf
1702
+ <promise>.as(<object>)
1703
+ <promise>.as(<constructor>)
1704
+ -> <promise-proxy>
1705
+ ```
1706
+
1707
+ A proxy promise will be populated with proxy methods to all the methods of the `<object>` or `<constructor>.prototype`.
1708
+
1709
+ #### `<promise-proxy>.<method>(..)`
1710
+
1711
+ When `<promise>` resolves, call the `.<method>(..)` on the resolved value.
1712
+
1713
+ ```bnf
1714
+ <promise-proxy>.<method>(..)
1715
+ -> <method-promise>
1716
+ ```
1717
+
1718
+ `<method-promise>` will resolve the the return value of the `<method>` when
1719
+ the main `<promise>` is resolved.
1720
+
1721
+
1722
+
1624
1723
  ## Generator extensions and utilities
1625
1724
 
1626
1725
  ```javascript
package/RegExp.js CHANGED
@@ -64,7 +64,8 @@ object.Mixin('RegExpProtoMixin', 'soft', {
64
64
 
65
65
 
66
66
  RegExpMixin(RegExp)
67
- RegExpProtoMixin(RegExp.prototype)
67
+ // XXX EXPEREMENTAL...
68
+ //RegExpProtoMixin(RegExp.prototype)
68
69
 
69
70
 
70
71
  var quoteRegExp =
package/generator.js CHANGED
@@ -210,6 +210,7 @@ object.Mixin('GeneratorMixin', 'soft', {
210
210
  map: makeGenerator('map'),
211
211
  filter: makeGenerator('filter'),
212
212
  reduce: makeGenerator('reduce'),
213
+ reduceRight: makeGenerator('reduceRight'),
213
214
 
214
215
  // non-generators...
215
216
  //
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ig-types",
3
- "version": "6.10.1",
3
+ "version": "6.11.2",
4
4
  "description": "Generic JavaScript types and type extensions...",
5
5
  "main": "main.js",
6
6
  "scripts": {