ig-types 6.14.0 → 6.15.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/Array.js CHANGED
@@ -139,7 +139,8 @@ var makeChunkIter = function(iter, wrapper){
139
139
  try {
140
140
  // handle iteration...
141
141
  res.push(
142
- val = (chunk = chunks.shift())[iter](_wrapper, ...rest))
142
+ val = (chunk = chunks.shift())
143
+ [iter](_wrapper, ...rest))
143
144
  // handle chunk...
144
145
  postChunk
145
146
  && postChunk.call(that,
@@ -319,9 +320,12 @@ object.Mixin('ArrayProtoMixin', 'soft', {
319
320
  // NOTE: order is preserved...
320
321
  unique: function(normalize){
321
322
  return normalize ?
322
- [...new Map(this.map(function(e){ return [normalize(e), e] })).values()]
323
- // NOTE: we are calling .compact() here to avoid creating undefined
324
- // items from empty slots in sparse arrays...
323
+ [...new Map(this
324
+ .map(function(e){
325
+ return [normalize(e), e] }))
326
+ .values()]
327
+ // NOTE: we are calling .compact() here to avoid creating
328
+ // undefined items from empty slots in sparse arrays...
325
329
  : [...new Set(this.compact())] },
326
330
  tailUnique: function(normalize){
327
331
  return this
@@ -336,8 +340,8 @@ object.Mixin('ArrayProtoMixin', 'soft', {
336
340
  // self to other (internal) while match compares two entities
337
341
  // externally.
338
342
  // XXX not sure if we need the destinction in name, will have to
339
- // come back to this when refactoring diff.js -- all three have
340
- // to be similar...
343
+ // come back to this when refactoring diff.js -- all three
344
+ // have to be similar...
341
345
  cmp: function(other){
342
346
  if(this === other){
343
347
  return true }
@@ -353,7 +357,8 @@ object.Mixin('ArrayProtoMixin', 'soft', {
353
357
  // NOTE: this will ignore order and repeating elments...
354
358
  setCmp: function(other){
355
359
  return this === other
356
- || (new Set([...this, ...other])).length == (new Set(this)).length },
360
+ || (new Set([...this, ...other])).length
361
+ == (new Set(this)).length },
357
362
 
358
363
  // Sort as the other array...
359
364
  //
@@ -369,12 +374,13 @@ object.Mixin('ArrayProtoMixin', 'soft', {
369
374
  // This will sort the intersecting items in the head keeping the rest
370
375
  // of the items in the same relative order...
371
376
  //
372
- // NOTE: if an item is in the array multiple times only the first index
373
- // is used...
377
+ // NOTE: if an item is in the array multiple times only the first
378
+ // index is used...
374
379
  //
375
380
  // XXX should this extend/patch .sort(..)???
376
- // ...currently do not see a clean way to do this without extending
377
- // and replacing Array or directly re-wrapping .sort(..)...
381
+ // ...currently do not see a clean way to do this without
382
+ // extending and replacing Array or directly re-wrapping
383
+ // .sort(..)...
378
384
  sortAs: function(other, place='head'){
379
385
  place = place == 'tail' ? -1 : 1
380
386
  // NOTE: the memory overhead here is better than the time overhead
@@ -441,8 +447,8 @@ object.Mixin('ArrayProtoMixin', 'soft', {
441
447
 
442
448
  // Convert an array to a map...
443
449
  //
444
- // This is similar to Array.prototype.toKeys(..) but does not restrict
445
- // value type to string.
450
+ // This is similar to Array.prototype.toKeys(..) but does not
451
+ // restrict value type to string.
446
452
  //
447
453
  // Format:
448
454
  // Map([
package/Promise.js CHANGED
@@ -5,8 +5,7 @@
5
5
  * Promise.iter(seq)
6
6
  * <promise>.iter()
7
7
  * Iterable promise object.
8
- * Similar to Promise.all(..) but adds basic iterator/generator
9
- * API and will resolve the items as they are ready (resolved).
8
+ * Similar to Promise.all(..) but adds basic iterator API.
10
9
  *
11
10
  * Promise.interactive(handler)
12
11
  * Interactive promise object.
@@ -39,31 +38,37 @@ var object = require('ig-object')
39
38
  // Like Promise.all(..) but adds ability to iterate through results
40
39
  // via generators .map(..)/.reduce(..) and friends...
41
40
  //
42
- // NOTE: it would be nice to support throwing STOP from the iterable
43
- // promise but...
44
- // - this is more complicated than simply using .smap(..) instead
45
- // of .map(..) because the list can contain async promises...
46
- // ...would need to wrap each .then(..) call in try-catch and
47
- // manually handle the stop...
48
- // ...then there's a question of derivative iterators etc.
49
- // - another issue here is that the stop would happen in order of
50
- // execution and not order of elements...
51
- // XXX though stopping within a single level might be useful...
52
- //
53
-
41
+ // NOTE: the following can not be implemented here:
42
+ // .splice(..) - can't both modify and return
43
+ // a result...
44
+ // .pop() / .shift() - can't modify the promise, use
45
+ // .first() / .last() instead.
46
+ // [Symbol.iterator]() - needs to be sync and we can't
47
+ // know the number of elements to
48
+ // return promises before the whole
49
+ // iterable promise is resolved.
54
50
  // NOTE: we are not using async/await here as we need to control the
55
51
  // type of promise returned in cases where we know we are returning
56
52
  // an array...
57
- // XXX should these be exported???
53
+ // NOTE: there is no point in implementing a 1:1 version of this that
54
+ // would not support element expansion/contraction as it would only
55
+ // simplify a couple of methods that are 1:1 (like .map(..) and
56
+ // .some(..)) while methods like .filter(..) will throw everything
57
+ // back to the complex IterablePromise...
58
+ //
59
+ // XXX how do we handle errors/rejections???
60
+ // ...mostly the current state is OK, but need more testing...
61
+ //
62
+
58
63
  var iterPromiseProxy =
59
- //module.iterPromiseProxy =
64
+ module.iterPromiseProxy =
60
65
  function(name){
61
66
  return function(...args){
62
67
  return this.constructor(
63
68
  this.then(function(lst){
64
69
  return lst[name](...args) })) } }
65
70
  var promiseProxy =
66
- //module.promiseProxy =
71
+ module.promiseProxy =
67
72
  function(name){
68
73
  return async function(...args){
69
74
  return (await this)[name](...args) } }
@@ -71,6 +76,13 @@ function(name){
71
76
  var IterablePromise =
72
77
  module.IterablePromise =
73
78
  object.Constructor('IterablePromise', Promise, {
79
+ get STOP(){
80
+ return Array.STOP },
81
+
82
+ }, {
83
+ // packed array...
84
+ //
85
+ // Holds promise state.
74
86
  //
75
87
  // Format:
76
88
  // [
@@ -81,22 +93,35 @@ object.Constructor('IterablePromise', Promise, {
81
93
  // ]
82
94
  //
83
95
  // This format has several useful features:
84
- // - concatenating packed list results in a packed list
96
+ // - concatenating packed lists results in a packed list
85
97
  // - adding an iterable promise (as-is) into a packed list results
86
98
  // in a packed list
87
99
  //
88
100
  // NOTE: in general iterable promises are implicitly immutable, so
89
- // it is not recomended to ever edit this inplace...
90
- __list: null,
101
+ // it is not recomended to ever edit this in-place...
102
+ // NOTE: we are not isolating or "protecting" any internals to
103
+ // enable users to responsibly extend the code.
104
+ __packed: null,
91
105
 
92
- // low-level .__list handlers/helpers...
106
+ // low-level .__packed handlers/helpers...
93
107
  //
94
108
  // NOTE: these can be useful for debugging and extending...
95
- __pack: function(list, handler){
109
+ //
110
+ // pack and oprionally transform/handle an array (sync)...
111
+ //
112
+ // NOTE: if 'types/Array' is imported this will support throwing STOP
113
+ // from the handler.
114
+ // Due to the async nature of promises though the way stops are
115
+ // handled may be unpredictable -- the handlers can be run out
116
+ // of order, as the nested promises resolve and thus throwing
117
+ // stop will stop the handlers not yet run and not the next
118
+ // handlers in sequence.
119
+ // XXX EXPEREMENTAL: STOP...
120
+ __pack: function(list, handler=undefined){
96
121
  var that = this
97
122
  // handle iterable promise list...
98
123
  if(list instanceof IterablePromise){
99
- return this.__handle(list.__list, handler) }
124
+ return this.__handle(list.__packed, handler) }
100
125
  // handle promise list...
101
126
  if(list instanceof Promise){
102
127
  return list.then(function(list){
@@ -108,6 +133,57 @@ object.Constructor('IterablePromise', Promise, {
108
133
  handler = handler
109
134
  ?? function(elem){
110
135
  return [elem] }
136
+
137
+ //* XXX EXPEREMENTAL: STOP...
138
+ var stoppable = false
139
+ var stop = false
140
+ var map = 'map'
141
+ var pack = function(){
142
+ return [list].flat()
143
+ [map](function(elem){
144
+ return elem && elem.then ?
145
+ (stoppable ?
146
+ // stoppable -- need to handle stop async...
147
+ elem
148
+ .then(function(res){
149
+ return !stop ?
150
+ handler(res)
151
+ : [] })
152
+ // NOTE: we are using .catch(..) here
153
+ // instead of directly passing the
154
+ // error handler to be able to catch
155
+ // the STOP from the handler...
156
+ .catch(handleSTOP)
157
+ // non-stoppable...
158
+ : elem.then(handler))
159
+ : elem instanceof Array ?
160
+ handler(elem)
161
+ // NOTE: we keep things that do not need protecting
162
+ // from .flat() as-is...
163
+ : !handle ?
164
+ elem
165
+ : handler(elem) }) }
166
+
167
+ // pack (stoppable)...
168
+ if(!!this.constructor.STOP){
169
+ stoppable = true
170
+ map = 'smap'
171
+ var handleSTOP = function(err){
172
+ stop = err
173
+ if(err === that.constructor.STOP
174
+ || err instanceof that.constructor.STOP){
175
+ return 'value' in err ?
176
+ err.value
177
+ : [] }
178
+ throw err }
179
+ try{
180
+ return pack()
181
+ }catch(err){
182
+ return handleSTOP(err) } }
183
+
184
+ // pack (non-stoppable)...
185
+ return pack() },
186
+ /*/
111
187
  return [list].flat()
112
188
  .map(function(elem){
113
189
  return elem && elem.then ?
@@ -120,11 +196,27 @@ object.Constructor('IterablePromise', Promise, {
120
196
  : !handle ?
121
197
  elem
122
198
  : handler(elem) }) },
123
- __handle: function(list, handler){
199
+ //*/
200
+ // transform/handle packed array (sync)...
201
+ //
202
+ // XXX BUG:
203
+ // await Promise.iter(['a', Promise.resolve(222), ['c']])
204
+ // .map(async e => e)
205
+ // -> ['a', <promise>, ['c']]
206
+ // is not the same as:
207
+ // await Promise.iter(['a', Promise.resolve(222), ['c']])
208
+ // .map(e => e)
209
+ // -> ['a', 222, ['c']]
210
+ // ...and these works as expected:
211
+ // await Promise.iter(['a', Promise.resolve(222), ['c']], async e => [e])
212
+ // -> ['a', 222, ['c']]
213
+ // await Promise.iter(['a', Promise.resolve(222), ['c']], e => [e])
214
+ // -> ['a', 222, ['c']]
215
+ __handle: function(list, handler=undefined){
124
216
  var that = this
125
217
  if(typeof(list) == 'function'){
126
218
  handler = list
127
- list = this.__list }
219
+ list = this.__packed }
128
220
  if(!handler){
129
221
  return list }
130
222
  // handle promise list...
@@ -135,58 +227,45 @@ object.Constructor('IterablePromise', Promise, {
135
227
  // NOTE: since each section of the packed .__array is the same
136
228
  // structure as the input we'll use .__pack(..) to handle
137
229
  // them, this also keeps all the handling code in one place.
230
+ //* XXX EXPEREMENTAL: STOP...
231
+ var map = !!this.constructor.STOP ?
232
+ 'smap'
233
+ : 'map'
234
+ return list[map](function(elem){
235
+ /*/
138
236
  return list.map(function(elem){
237
+ //*/
139
238
  return elem instanceof Array ?
140
239
  that.__pack(elem, handler)
141
240
  : elem instanceof Promise ?
142
241
  that.__pack(elem, handler)
143
- .then(function(elem){
144
- return elem.flat() })
242
+ //.then(function(elem){
243
+ .then(function([elem]){
244
+ return elem })
145
245
  : [handler(elem)] })
146
246
  .flat() },
147
- __unpack: function(list){
247
+ // unpack array (async)...
248
+ __unpack: async function(list){
148
249
  list = list
149
- ?? this.__list
250
+ ?? this.__packed
150
251
  // handle promise list...
151
- if(list instanceof Promise){
152
- var that = this
153
- return list.then(function(list){
154
- return that.__unpack(list) }) }
155
- // do the work...
156
- return Promise.all(list)
157
- .then(function(list){
158
- return list.flat() }) },
252
+ return list instanceof Promise ?
253
+ this.__unpack(await list)
254
+ // do the work...
255
+ : (await Promise.all(list))
256
+ .flat() },
159
257
 
160
258
 
161
259
  // iterator methods...
162
260
  //
163
261
  // These will return a new IterablePromise instance...
164
262
  //
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
263
  // NOTE: these are different to Array's equivalents in that the handler
173
264
  // is called not in the order of the elements but rather in order
174
265
  // of promise resolution...
175
266
  // NOTE: index of items is unknowable because items can expand and
176
- // contract depending on handlrs (e.g. .filter(..) can remove
267
+ // contract depending on handlers (e.g. .filter(..) can remove
177
268
  // 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
269
  map: function(func){
191
270
  return this.constructor(this,
192
271
  function(e){
@@ -208,11 +287,11 @@ object.Constructor('IterablePromise', Promise, {
208
287
  : _filter(e) }) },
209
288
  // NOTE: this does not return an iterable promise as we can't know
210
289
  // what the user reduces to...
211
- // XXX we could look at the initial state though...
212
290
  // NOTE: the items can be handled out of order because the nested
213
291
  // promises can resolve in any order...
214
292
  // NOTE: since order of execution can not be guaranteed there is no
215
- // point in implementing .reduceRight(..)
293
+ // point in implementing .reduceRight(..) in the same way
294
+ // (see below)...
216
295
  reduce: function(func, res){
217
296
  return this.constructor(this,
218
297
  function(e){
@@ -232,7 +311,7 @@ object.Constructor('IterablePromise', Promise, {
232
311
  e
233
312
  : [e] }) },
234
313
  reverse: function(){
235
- var lst = this.__list
314
+ var lst = this.__packed
236
315
  return this.constructor(
237
316
  lst instanceof Promise ?
238
317
  lst.then(function(elems){
@@ -277,23 +356,21 @@ object.Constructor('IterablePromise', Promise, {
277
356
  return this.constructor([elem])
278
357
  .concat(this) },
279
358
 
280
- // XXX can we do these?
281
- // .pop()
282
- // .shift()
283
- // .splice(..)
284
- // ...would be nice if these could stop everything that's not
285
- // needed to execute -- likely not possible (XXX)
286
- // ...these need to somehow both return an element and affect
287
- // the iterator (or return a new one) -- we can trivially do either
288
- // one action within the spec but not both...
289
-
290
- // NOTE: this can avoid waiting for the whole promise to resolve only
291
- // for indexes 0 and -1, everything else is non-deterministic and
292
- // we'll have to wait for the whole thing to resolve.
359
+ // proxy methods...
360
+ //
361
+ // These require the whole promise to resolve to trigger.
362
+ //
363
+ // An exception to this would be .at(0)/.first() and .at(-1)/.last()
364
+ // that can get the target element if it's accessible.
365
+ //
366
+ // NOTE: methods that are guaranteed to return an array will return
367
+ // an iterable promise (created with iterPromiseProxy(..))...
368
+ //
293
369
  at: async function(i){
294
- var list = this.__list
370
+ var list = this.__packed
295
371
  return ((i != 0 && i != -1)
296
372
  || list instanceof Promise
373
+ // XXX not sure if this is correct...
297
374
  || list.at(i) instanceof Promise) ?
298
375
  (await this).at(i)
299
376
  // NOTE: we can only reason about first/last explicit elements,
@@ -308,24 +385,97 @@ object.Constructor('IterablePromise', Promise, {
308
385
  last: function(){
309
386
  return this.at(-1) },
310
387
 
388
+ // NOTE: unlike .reduce(..) this needs the parent fully resolved
389
+ // to be able to iterate from the end.
390
+ // XXX is it faster to do .reverse().reduce(..) ???
391
+ reduceRight: promiseProxy('reduceRight'),
392
+
311
393
  // NOTE: there is no way we can do a sync generator returning
312
- // promises for values because any promise in .__list makes the
313
- // value count/index non-deterministic...
394
+ // promises for values because any promise in .__packed makes
395
+ // the value count/index non-deterministic...
314
396
  sort: iterPromiseProxy('sort'),
315
397
  slice: iterPromiseProxy('slice'),
398
+
316
399
  entries: iterPromiseProxy('entries'),
317
400
  keys: iterPromiseProxy('keys'),
318
- // XXX we could possibly make this better via .map(..)
319
401
  values: iterPromiseProxy('values'),
320
402
 
321
403
  indexOf: promiseProxy('indexOf'),
404
+ lastIndexOf: promiseProxy('lastIndexOf'),
322
405
  includes: promiseProxy('includes'),
323
406
 
407
+ //
408
+ // .find(<func>)
409
+ // .find(<func>, 'value')
410
+ // -> <promise>(<value>)
411
+ //
412
+ // .find(<func>, 'result')
413
+ // -> <promise>(<result>)
414
+ //
415
+ // .find(<func>, 'bool')
416
+ // -> <promise>(<bool>)
417
+ //
418
+ // NOTE: this is slightly different to Array's .find(..) in that it
419
+ // accepts the result value enabling returning both the value
420
+ // itself ('value', default), the test function's result
421
+ // ('result') or true/false ('bool') -- this is added to be
422
+ // able to distinguish between the undefined as a stored value
423
+ // and undefined as a "nothing found" result.
424
+ // NOTE: I do not get how essentially identical methods .some(..)
425
+ // and .find(..) got added to JS's Array...
426
+ // the only benefit is that .some(..) handles undefined values
427
+ // stored in the array better...
428
+ // NOTE: this will return the result as soon as it's available but
429
+ // it will not stop the created but unresolved at the time
430
+ // promises from executing, this is both good and bad:
431
+ // + it will not break other clients waiting for promises
432
+ // to resolve...
433
+ // - if no clients are available this can lead to wasted
434
+ // CPU time...
435
+ find: async function(func, result='value'){
436
+ var that = this
437
+ // NOTE: not using pure await here as this is simpler to actually
438
+ // control the moment the resulting promise resolves without
439
+ // the need for juggling state...
440
+ return new Promise(function(resolve, reject){
441
+ var resolved = false
442
+ that.map(function(elem){
443
+ var res = func(elem)
444
+ if(res){
445
+ resolved = true
446
+ resolve(
447
+ result == 'bool' ?
448
+ true
449
+ : result == 'result' ?
450
+ res
451
+ : elem)
452
+ // XXX EXPEREMENTAL: STOP...
453
+ // NOTE: we do not need to throw STOP here
454
+ // but it can prevent some overhead...
455
+ if(that.constructor.STOP){
456
+ throw that.constructor.STOP } } })
457
+ .then(function(){
458
+ resolved
459
+ || resolve(
460
+ result == 'bool' ?
461
+ false
462
+ : undefined) }) }) },
463
+ findIndex: promiseProxy('findIndex'),
464
+
465
+ // NOTE: this is just a special-case of .find(..)
466
+ some: async function(func){
467
+ return this.find(func, 'bool') },
324
468
  every: promiseProxy('every'),
325
- // XXX this can be lazy...
326
- some: promiseProxy('some'),
327
469
 
328
470
 
471
+ // this is defined globally as Promise.prototype.iter(..)
472
+ //
473
+ // for details see: PromiseMixin(..) below...
474
+ //iter: function(handler=undefined){ ... },
475
+
476
+
477
+ // promise api...
478
+ //
329
479
  // Overload .then(..), .catch(..) and .finally(..) to return a plain
330
480
  // Promise instnace...
331
481
  //
@@ -351,6 +501,7 @@ object.Constructor('IterablePromise', Promise, {
351
501
  : p },
352
502
 
353
503
 
504
+ // constructor...
354
505
  //
355
506
  // Promise.iter([ .. ])
356
507
  // -> iterable-promise
@@ -370,11 +521,12 @@ object.Constructor('IterablePromise', Promise, {
370
521
  // items...
371
522
  // XXX we can make the index a promise, then if the client needs
372
523
  // the value they can wait for it...
524
+ // ...this may be quite an overhead...
373
525
  //
374
526
  //
375
527
  // Special cases useful for extending this constructor...
376
528
  //
377
- // Set raw .__list without any pre-processing...
529
+ // Set raw .__packed without any pre-processing...
378
530
  // Promise.iter([ .. ], 'raw')
379
531
  // -> iterable-promise
380
532
  //
@@ -383,11 +535,9 @@ object.Constructor('IterablePromise', Promise, {
383
535
  // -> iterable-promise
384
536
  //
385
537
  //
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???
538
+ // NOTE: if 'types/Array' is imported this will support throwing STOP,
539
+ // for more info see notes for .__pack(..)
540
+ // XXX EXPEREMENTAL: STOP...
391
541
  __new__: function(_, list, handler){
392
542
  // instance...
393
543
  var promise
@@ -408,9 +558,9 @@ object.Constructor('IterablePromise', Promise, {
408
558
  // handle/pack input data...
409
559
  if(handler != 'raw'){
410
560
  list = list instanceof IterablePromise ?
411
- this.__handle(list.__list, handler)
561
+ this.__handle(list.__packed, handler)
412
562
  : this.__pack(list, handler) }
413
- Object.defineProperty(obj, '__list', {
563
+ Object.defineProperty(obj, '__packed', {
414
564
  value: list,
415
565
  enumerable: false,
416
566
  })
@@ -473,13 +623,14 @@ object.Constructor('InteractivePromise', Promise, {
473
623
  // register a handler...
474
624
  } else {
475
625
  var h = obj == null ?
476
- // NOTE: we need to get the handlers from .__message_handlers
477
- // unless we are not fully defined yet, then use the
478
- // bootstrap container (handlers)...
479
- // ...since we can call onmessage(..) while the promise
480
- // is still defined there is no way to .send(..) until it
481
- // returns a promise object, this races here are highly
482
- // unlikely...
626
+ // NOTE: we need to get the handlers from
627
+ // .__message_handlers unless we are not
628
+ // fully defined yet, then use the bootstrap
629
+ // container (handlers)...
630
+ // ...since we can call onmessage(..) while
631
+ // the promise is still defined there is no
632
+ // way to .send(..) until it returns a promise
633
+ // object, this races here are highly unlikely...
483
634
  handlers
484
635
  : (obj.__message_handlers =
485
636
  obj.__message_handlers ?? [])
@@ -507,6 +658,7 @@ object.Constructor('InteractivePromise', Promise, {
507
658
  // Cooperative promise...
508
659
  //
509
660
  // A promise that can be resolved/rejected externally.
661
+ //
510
662
  // NOTE: normally this has no internal resolver logic...
511
663
  //
512
664
 
@@ -566,10 +718,13 @@ object.Constructor('CooperativePromise', Promise, {
566
718
  var ProxyPromise =
567
719
  module.ProxyPromise =
568
720
  object.Constructor('ProxyPromise', Promise, {
569
- __new__: function(context, constructor){
570
- var proto = 'prototype' in constructor ?
571
- constructor.prototype
572
- : constructor
721
+
722
+ then: IterablePromise.prototype.then,
723
+
724
+ __new__: function(context, other, nooverride=false){
725
+ var proto = 'prototype' in other ?
726
+ other.prototype
727
+ : other
573
728
  var obj = Reflect.construct(
574
729
  ProxyPromise.__proto__,
575
730
  [function(resolve, reject){
@@ -580,6 +735,9 @@ object.Constructor('ProxyPromise', Promise, {
580
735
  // NOTE: we are not using object.deepKeys(..) here as we need
581
736
  // the key origin not to trigger property getters...
582
737
  var seen = new Set()
738
+ nooverride = nooverride instanceof Array ?
739
+ new Set(nooverride)
740
+ : nooverride
583
741
  while(proto != null){
584
742
  Object.entries(Object.getOwnPropertyDescriptors(proto))
585
743
  .forEach(function([key, value]){
@@ -594,6 +752,13 @@ object.Constructor('ProxyPromise', Promise, {
594
752
  && Object.prototype.run === value.value)
595
753
  && !value.enumerable){
596
754
  return }
755
+ // do not override existing methods...
756
+ if(nooverride === true ?
757
+ key in obj
758
+ : nooverride instanceof Set ?
759
+ nooverride.has(key)
760
+ : nooverride){
761
+ return }
597
762
  // proxy...
598
763
  obj[key] = promiseProxy(key) })
599
764
  proto = proto.__proto__ }
@@ -619,7 +784,7 @@ var PromiseProtoMixin =
619
784
  module.PromiseProtoMixin =
620
785
  object.Mixin('PromiseProtoMixin', 'soft', {
621
786
  as: ProxyPromise,
622
- iter: function(handler){
787
+ iter: function(handler=undefined){
623
788
  return IterablePromise(this, handler) },
624
789
  })
625
790
 
@@ -629,4 +794,4 @@ PromiseProtoMixin(Promise.prototype)
629
794
 
630
795
 
631
796
  /**********************************************************************
632
- * vim:set ts=4 sw=4 : */ return module })
797
+ * vim:set ts=4 sw=4 nowrap : */ return module })
package/README.md CHANGED
@@ -77,8 +77,14 @@ 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
+ - [`<promise-iter>.some(..)` / `<promise-iter>.find(..)`](#promise-itersome--promise-iterfind)
82
+ - [Array proxy methods returning `<promise-iter>`](#array-proxy-methods-returning-promise-iter)
83
+ - [Array proxy methods returning a `<promise>`](#array-proxy-methods-returning-a-promise)
80
84
  - [`<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally)
85
+ - [`promise.IterablePromise.STOP` / `promise.IterablePromise.STOP(..)`](#promiseiterablepromisestop--promiseiterablepromisestop)
81
86
  - [Advanced handler](#advanced-handler)
87
+ - [Stopping the iteration](#stopping-the-iteration)
82
88
  - [Promise proxies](#promise-proxies)
83
89
  - [`<promise>.as(..)`](#promiseas)
84
90
  - [`<promise-proxy>.<method>(..)`](#promise-proxymethod)
@@ -1663,6 +1669,95 @@ and [`<array>.unshift(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScr
1663
1669
  see them for more info.
1664
1670
 
1665
1671
 
1672
+ #### `<promise-iter>.at(..)` / `<promise-iter>.first()` / `<promise-iter>.last()`
1673
+
1674
+ Proxies to the appropriate array methods with a special-case: when getting elements
1675
+ at positions `0` or `-1` (i.e. `.first()` / `.last()`) these _can_ resolve before the
1676
+ parent `<promise-iter>`.
1677
+
1678
+ XXX
1679
+
1680
+ #### `<promise-iter>.some(..)` / `<promise-iter>.find(..)`
1681
+
1682
+ ```bnf
1683
+ <promise-iter>.some(<func>)
1684
+ -> <promise>
1685
+
1686
+ <promise-iter>.find(<func>)
1687
+ -> <promise>
1688
+ ```
1689
+
1690
+ The main difference between `.some(..)` and `.find(..)` is in that the `<promise>`
1691
+ returned from the former will resolve to either `true` or `false`, and in the later
1692
+ to the found value or `undefined`.
1693
+
1694
+ `.find(..)` supports an additional argument that controls what returned `<promise>`
1695
+ is resolved to...
1696
+
1697
+ ```bnf
1698
+ <promise-iter>.find(<func>)
1699
+ <promise-iter>.find(<func>, 'value')
1700
+ -> <promise>
1701
+
1702
+ <promise-iter>.find(<func>, 'bool')
1703
+ -> <promise>
1704
+
1705
+ <promise-iter>.find(<func>, 'result')
1706
+ -> <promise>
1707
+ ```
1708
+
1709
+ - `value` (default)
1710
+ resolve to the stored value if found and `undefined` otherwise.
1711
+ - `bool`
1712
+ resolve to `true` if the value is found and `false` otherwise, this is how
1713
+ `.some(..)` is impelemnted.
1714
+ - `result`
1715
+ resolve to the return value of the test `<func>`.
1716
+
1717
+ These are similar to [`<array>.some(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
1718
+ and [`<array>.find(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
1719
+ see them for more info.
1720
+
1721
+ #### Array proxy methods returning `<promise-iter>`
1722
+
1723
+ - `<promise-iter>.sort(..)`
1724
+ - `<promise-iter>.slice(..)`
1725
+ - `<promise-iter>.entries()` / `<promise-iter>.keys()` / `<promise-iter>.values()`
1726
+
1727
+ These methods are proxies to the appropriate array methods.
1728
+
1729
+ ```bnf
1730
+ <promise-iter>.<method>(..)
1731
+ -> <promise-iter>
1732
+ ```
1733
+
1734
+ These methods need the parent `<promise-iter>` to resolve before resolving themselves.
1735
+
1736
+ XXX links...
1737
+
1738
+
1739
+ #### Array proxy methods returning a `<promise>`
1740
+
1741
+ - `<promise-iter>.indexOf(..)`
1742
+ - `<promise-iter>.includes(..)`
1743
+ - `<promise-iter>.every(..)`
1744
+ - `<promise-iter>.findIndex(..)`
1745
+
1746
+ These methods are proxies to the appropriate array methods.
1747
+
1748
+ ```bnf
1749
+ <promise-iter>.<method>(..)
1750
+ -> <promise>
1751
+ ```
1752
+
1753
+ These methods need the parent `<promise-iter>` to resolve before resolving themselves.
1754
+
1755
+ Since the equivalent array methods do not return iterables these will return a basic
1756
+ (non-iterable) `<promise>`.
1757
+
1758
+ XXX links...
1759
+
1760
+
1666
1761
  #### `<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`
1667
1762
 
1668
1763
  An extension to
@@ -1676,6 +1771,16 @@ this adds the ability to pass no arguments
1676
1771
  This will return a generic promise wrapper passing through the results as-is. This
1677
1772
  can be useful to hide the extended promise API from further code.
1678
1773
 
1774
+ #### `promise.IterablePromise.STOP` / `promise.IterablePromise.STOP(..)`
1775
+
1776
+ A special object that when thrown from a function/promise handler will stop
1777
+ further iteration.
1778
+
1779
+ This is `undefined` until the `ig-types/Array` module is loaded.
1780
+
1781
+ For more info see: [Stopping the iteration](#stopping-the-iteration) below, and
1782
+ [the 'Array' STOP section](#arraystop--arraystop)
1783
+
1679
1784
 
1680
1785
  #### Advanced handler
1681
1786
 
@@ -1727,6 +1832,24 @@ var p = Promise.iter(
1727
1832
  console.log(lst) }) // -> [2, 2, 4, 4, [5, 6]]
1728
1833
  ```
1729
1834
 
1835
+ #### Stopping the iteration
1836
+
1837
+ Like the [`Array`](#arraystop--arraystop) module, this support throwing `STOP` to
1838
+ stop iteration. As we uses [`.smap(..)`](#arraysmap--arraysfilter--arraysreduce--arraysforeach)
1839
+ stopping support is supported if `ig-types/Array` module is loaded.
1840
+
1841
+ ```javascript
1842
+ require('ig-types/Array')
1843
+ ```
1844
+
1845
+ This is also different semantically, as promise iteration can happen out of order,
1846
+ stopping affects the order of processing and not order of the input array with one exception: promises already created can not be stopped in `JavaScript`.
1847
+
1848
+ Any handler function passed to a `<promise-iter>` method can `throw` a STOP.
1849
+
1850
+ For more details see: [the 'Array' STOP section](#arraystop--arraystop)
1851
+
1852
+
1730
1853
 
1731
1854
  ### Promise proxies
1732
1855
 
package/generator.js CHANGED
@@ -66,6 +66,14 @@ module.Generator =
66
66
  (function*(){}).constructor
67
67
 
68
68
 
69
+ var AsyncGeneratorPrototype =
70
+ (async function*(){}).constructor.prototype
71
+
72
+ var AsyncGenerator =
73
+ module.AsyncGenerator =
74
+ (async function*(){}).constructor
75
+
76
+
69
77
  // base iterator prototypes...
70
78
  var ITERATOR_PROTOTYPES = [
71
79
  Array,
@@ -428,6 +436,41 @@ ITERATOR_PROTOTYPES
428
436
  GeneratorProtoMixin(proto) })
429
437
 
430
438
 
439
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
440
+ // XXX EXPERIMENTAL...
441
+
442
+ var makeAsyncGenerator = function(name, pre){
443
+ return function(...args){
444
+ var that = this
445
+ return Object.assign(
446
+ async function*(){
447
+ var a = pre ?
448
+ pre.call(this, args, ...arguments)
449
+ : args
450
+ for await (var e of that(...arguments)[name](...a)){
451
+ yield e } },
452
+ { toString: function(){
453
+ return [
454
+ that.toString(),
455
+ // XXX need to normalize args better...
456
+ `.${ name }(${ args.join(', ') })`,
457
+ ].join('\n ') }, }) } }
458
+
459
+ var AsyncGeneratorMixin =
460
+ module.AsyncGeneratorMixin =
461
+ object.Mixin('AsyncGeneratorMixin', 'soft', {
462
+ map: makeAsyncGenerator('map'),
463
+ })
464
+
465
+ var AsyncGeneratorProtoMixin =
466
+ module.AsyncGeneratorProtoMixin =
467
+ object.Mixin('AsyncGeneratorProtoMixin', 'soft', {
468
+ })
469
+
470
+ //AsyncGeneratorMixin(AsyncGeneratorPrototype)
471
+ //AsyncGeneratorProtoMixin(AsyncGeneratorPrototype.prototype)
472
+
473
+
431
474
 
432
475
  //---------------------------------------------------------------------
433
476
  // Generators...
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ig-types",
3
- "version": "6.14.0",
3
+ "version": "6.15.1",
4
4
  "description": "Generic JavaScript types and type extensions...",
5
5
  "main": "main.js",
6
6
  "scripts": {