ig-types 6.13.7 → 6.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/Promise.js +92 -36
  2. package/README.md +11 -0
  3. package/package.json +1 -1
package/Promise.js CHANGED
@@ -1,11 +1,9 @@
1
1
  /**********************************************************************
2
- *
3
- *
4
- *
5
2
  *
6
3
  * This defines the following extensions to Promise:
7
4
  *
8
5
  * Promise.iter(seq)
6
+ * <promise>.iter()
9
7
  * Iterable promise object.
10
8
  * Similar to Promise.all(..) but adds basic iterator/generator
11
9
  * API and will resolve the items as they are ready (resolved).
@@ -19,6 +17,11 @@
19
17
  * Exposes the API to resolve/reject the promise object
20
18
  * externally.
21
19
  *
20
+ * <promise>.as(obj)
21
+ * Promise proxy.
22
+ * Proxies the methods available from obj to promise value.
23
+ *
24
+ *
22
25
  *
23
26
  *
24
27
  **********************************************/ /* c8 ignore next 2 */
@@ -28,18 +31,6 @@
28
31
 
29
32
  var object = require('ig-object')
30
33
 
31
- // XXX required for STOP...
32
- //var generator = require('./generator')
33
-
34
-
35
- /*********************************************************************/
36
-
37
- /* XXX not used yet...
38
- // NOTE: this is used in a similar fashion to Python's StopIteration...
39
- var STOP =
40
- module.STOP =
41
- object.STOP
42
- //*/
43
34
 
44
35
 
45
36
  //---------------------------------------------------------------------
@@ -48,13 +39,38 @@ module.STOP =
48
39
  // Like Promise.all(..) but adds ability to iterate through results
49
40
  // via generators .map(..)/.reduce(..) and friends...
50
41
  //
42
+ // NOTE: it would be nice to support throwing STOP from the iterable
43
+ // promise but...
44
+ // - this is more complicated than simply using .smap(..) instead
45
+ // of .map(..) because the list can contain async promises...
46
+ // ...would need to wrap each .then(..) call in try-catch and
47
+ // manually handle the stop...
48
+ // ...then there's a question of derivative iterators etc.
49
+ // - another issue here is that the stop would happen in order of
50
+ // execution and not order of elements...
51
+ // XXX though stopping within a single level might be useful...
52
+ //
53
+
54
+ // NOTE: we are not using async/await here as we need to control the
55
+ // type of promise returned in cases where we know we are returning
56
+ // an array...
57
+ // XXX should these be exported???
58
+ var iterPromiseProxy =
59
+ //module.iterPromiseProxy =
60
+ function(name){
61
+ return function(...args){
62
+ return this.constructor(
63
+ this.then(function(lst){
64
+ return lst[name](...args) })) } }
65
+ var promiseProxy =
66
+ //module.promiseProxy =
67
+ function(name){
68
+ return async function(...args){
69
+ return (await this)[name](...args) } }
51
70
 
52
71
  var IterablePromise =
53
72
  module.IterablePromise =
54
73
  object.Constructor('IterablePromise', Promise, {
55
- // XXX
56
- //STOP: object.STOP,
57
-
58
74
  //
59
75
  // Format:
60
76
  // [
@@ -64,6 +80,13 @@ object.Constructor('IterablePromise', Promise, {
64
80
  // ...
65
81
  // ]
66
82
  //
83
+ // This format has several useful features:
84
+ // - concatenating packed list results in a packed list
85
+ // - adding an iterable promise (as-is) into a packed list results
86
+ // in a packed list
87
+ //
88
+ // NOTE: in general iterable promises are implicitly immutable, so
89
+ // it is not recomended to ever edit this inplace...
67
90
  __list: null,
68
91
 
69
92
  // low-level .__list handlers/helpers...
@@ -163,6 +186,7 @@ object.Constructor('IterablePromise', Promise, {
163
186
  // .includes(..)
164
187
  // .some(..) / .every(..)
165
188
  // .sort(..)
189
+ // XXX update this note...
166
190
  map: function(func){
167
191
  return this.constructor(this,
168
192
  function(e){
@@ -196,6 +220,7 @@ object.Constructor('IterablePromise', Promise, {
196
220
  return [] })
197
221
  .then(function(){
198
222
  return res }) },
223
+
199
224
  flat: function(depth=1){
200
225
  return this.constructor(this,
201
226
  function(e){
@@ -252,14 +277,54 @@ object.Constructor('IterablePromise', Promise, {
252
277
  return this.constructor([elem])
253
278
  .concat(this) },
254
279
 
255
- // XXX do we need these?
280
+ // XXX can we do these?
256
281
  // .pop()
257
282
  // .shift()
258
- // .first() / .last()
259
- // .at(..)
283
+ // .splice(..)
260
284
  // ...would be nice if these could stop everything that's not
261
- // needed to execute...
285
+ // needed to execute -- likely not possible (XXX)
286
+ // ...these need to somehow both return an element and affect
287
+ // the iterator (or return a new one) -- we can trivially do either
288
+ // one action within the spec but not both...
289
+
290
+ // NOTE: this can avoid waiting for the whole promise to resolve only
291
+ // for indexes 0 and -1, everything else is non-deterministic and
292
+ // we'll have to wait for the whole thing to resolve.
293
+ at: async function(i){
294
+ var list = this.__list
295
+ return ((i != 0 && i != -1)
296
+ || list instanceof Promise
297
+ || list.at(i) instanceof Promise) ?
298
+ (await this).at(i)
299
+ // NOTE: we can only reason about first/last explicit elements,
300
+ // anything else is non-deterministic...
301
+ : list.at(i) instanceof Promise ?
302
+ [await list.at(i)].flat().at(i)
303
+ : list.at(i) instanceof Array ?
304
+ list.at(i).at(i)
305
+ : list.at(i) },
306
+ first: function(){
307
+ return this.at(0) },
308
+ last: function(){
309
+ return this.at(-1) },
262
310
 
311
+ // NOTE: there is no way we can do a sync generator returning
312
+ // promises for values because any promise in .__list makes the
313
+ // value count/index non-deterministic...
314
+ sort: iterPromiseProxy('sort'),
315
+ slice: iterPromiseProxy('slice'),
316
+ entries: iterPromiseProxy('entries'),
317
+ keys: iterPromiseProxy('keys'),
318
+ // XXX we could possibly make this better via .map(..)
319
+ values: iterPromiseProxy('values'),
320
+
321
+ indexOf: promiseProxy('indexOf'),
322
+ includes: promiseProxy('includes'),
323
+
324
+ every: promiseProxy('every'),
325
+ // XXX this can be lazy...
326
+ some: promiseProxy('some'),
327
+
263
328
 
264
329
  // Overload .then(..), .catch(..) and .finally(..) to return a plain
265
330
  // Promise instnace...
@@ -295,8 +360,9 @@ object.Constructor('IterablePromise', Promise, {
295
360
  //
296
361
  //
297
362
  // handler(e)
298
- // -> [value]
363
+ // -> [value, ..]
299
364
  // -> []
365
+ // -> <promise>
300
366
  //
301
367
  //
302
368
  // NOTE: element index is unknowable until the full list is expanded
@@ -321,14 +387,7 @@ object.Constructor('IterablePromise', Promise, {
321
387
  // - do we unwind here or externally?
322
388
  // ...feels like with the generator external unwinding is
323
389
  // needed...
324
- // XXX would be nice to support throwing STOP...
325
- // - this is more complicated than simply suing .smap(..) instead
326
- // of .map(..) because the list can contain async promises...
327
- // ...would need to wrap each .then(..) call in try-catch and
328
- // manually handle the stop...
329
- // - another issue here is that the stop would happen in order of
330
- // execution and not order of elements...
331
- // XXX how do we handle errors???
390
+ // XXX how do we handle errors/rejections???
332
391
  __new__: function(_, list, handler){
333
392
  // instance...
334
393
  var promise
@@ -344,7 +403,7 @@ object.Constructor('IterablePromise', Promise, {
344
403
  promise = {resolve, reject} }],
345
404
  IterablePromise)
346
405
 
347
- // new instance...
406
+ // populate new instance...
348
407
  if(promise){
349
408
  // handle/pack input data...
350
409
  if(handler != 'raw'){
@@ -536,10 +595,7 @@ object.Constructor('ProxyPromise', Promise, {
536
595
  && !value.enumerable){
537
596
  return }
538
597
  // proxy...
539
- obj[key] = function(...args){
540
- // XXX should we also .catch(..) here???
541
- return context.then(function(res){
542
- return res[key](...args) }) } })
598
+ obj[key] = promiseProxy(key) })
543
599
  proto = proto.__proto__ }
544
600
  return obj },
545
601
  })
package/README.md CHANGED
@@ -1508,6 +1508,17 @@ promise, even if the original is resolved.
1508
1508
  If all values are resolved the `<promise-iter>` will resolve on the next
1509
1509
  execution frame.
1510
1510
 
1511
+ There are two types of iterator methods here, both are transparent but different
1512
+ in how they process values:
1513
+ - *Parallel methods*
1514
+ These handle elements as soon as they are available even if the parent promise
1515
+ is not yet resolved.
1516
+ <!-- XXX list -->
1517
+ - *Proxies*
1518
+ These methods simply wait for the main promise to resolve and then call the
1519
+ appropriate method on the result.
1520
+ <!-- XXX list + mark definitions as "(proxy)" -->
1521
+
1511
1522
  <!--
1512
1523
  XXX should we support generators as input?
1513
1524
  ...not sure about the control flow direction here, on one hand the generator
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ig-types",
3
- "version": "6.13.7",
3
+ "version": "6.14.0",
4
4
  "description": "Generic JavaScript types and type extensions...",
5
5
  "main": "main.js",
6
6
  "scripts": {