ig-types 6.12.0 → 6.13.4

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 (4) hide show
  1. package/Promise.js +134 -79
  2. package/README.md +17 -11
  3. package/package.json +1 -1
  4. package/test.js +143 -28
package/Promise.js CHANGED
@@ -58,6 +58,7 @@ object.Constructor('IterablePromise', Promise, {
58
58
  //
59
59
  // Format:
60
60
  // [
61
+ // <non-array-value>,
61
62
  // [ <value> ],
62
63
  // <promise>,
63
64
  // ...
@@ -65,6 +66,74 @@ object.Constructor('IterablePromise', Promise, {
65
66
  //
66
67
  __list: null,
67
68
 
69
+ // low-level .__list handlers/helpers...
70
+ //
71
+ // NOTE: these can be useful for debugging and extending...
72
+ __pack: function(list, handler){
73
+ var that = this
74
+ // handle iterable promise list...
75
+ if(list instanceof IterablePromise){
76
+ return this.__handle(list.__list, handler) }
77
+ // handle promise list...
78
+ if(list instanceof Promise){
79
+ return list.then(function(list){
80
+ return that.__pack(list, handler) }) }
81
+ // do the work...
82
+ // NOTE: packing and handling are mixed here because it's faster
83
+ // to do them both on a single list traverse...
84
+ var handle = !!handler
85
+ handler = handler
86
+ ?? function(elem){
87
+ return [elem] }
88
+ return [list].flat()
89
+ .map(function(elem){
90
+ return elem && elem.then ?
91
+ //that.__pack(elem, handler)
92
+ elem.then(handler)
93
+ : elem instanceof Array ?
94
+ handler(elem)
95
+ // NOTE: we keep things that do not need protecting
96
+ // from .flat() as-is...
97
+ : !handle ?
98
+ elem
99
+ : handler(elem) }) },
100
+ __handle: function(list, handler){
101
+ var that = this
102
+ if(typeof(list) == 'function'){
103
+ handler = list
104
+ list = this.__list }
105
+ if(!handler){
106
+ return list }
107
+ // handle promise list...
108
+ if(list instanceof Promise){
109
+ return list.then(function(list){
110
+ return that.__handle(list, handler) }) }
111
+ // do the work...
112
+ // NOTE: since each section of the packed .__array is the same
113
+ // structure as the input we'll use .__pack(..) to handle
114
+ // them, this also keeps all the handling code in one place.
115
+ return list.map(function(elem){
116
+ return elem instanceof Array ?
117
+ that.__pack(elem, handler)
118
+ : elem instanceof Promise ?
119
+ that.__pack(elem, handler)
120
+ .then(function(elem){
121
+ return elem.flat() })
122
+ : [handler(elem)] })
123
+ .flat() },
124
+ __unpack: function(list){
125
+ list = list
126
+ ?? this.__list
127
+ // handle promise list...
128
+ if(list instanceof Promise){
129
+ var that = this
130
+ return list.then(function(list){
131
+ return that.__unpack(list) }) }
132
+ // do the work...
133
+ return Promise.all(list)
134
+ .then(function(list){
135
+ return list.flat() }) },
136
+
68
137
 
69
138
  // iterator methods...
70
139
  //
@@ -99,21 +168,31 @@ object.Constructor('IterablePromise', Promise, {
99
168
  map: function(func){
100
169
  return this.constructor(this,
101
170
  function(e){
102
- return [func(e)] }) },
171
+ var res = func(e)
172
+ return res instanceof Promise ?
173
+ res.then(function(e){
174
+ return [e] })
175
+ : [res] }) },
103
176
  filter: function(func){
104
177
  return this.constructor(this,
105
178
  function(e){
106
- return func(e) ?
107
- [e]
108
- : [] }) },
179
+ var res = func(e)
180
+ var _filter = function(elem){
181
+ return res ?
182
+ [elem]
183
+ : [] }
184
+ return res instanceof Promise ?
185
+ res.then(_filter)
186
+ : _filter(e) }) },
109
187
  // NOTE: this does not return an iterable promise as we can't know
110
188
  // what the user reduces to...
111
189
  // XXX we could look at the initial state though...
112
190
  // NOTE: the items can be handled out of order because the nested
113
191
  // promises can resolve in any order.
114
- // XXX write how to go around this...
192
+ // XXX doc how to go around this...
115
193
  // NOTE: since order of execution can not be guaranteed there is no
116
194
  // point in implementing .reduceRight(..)
195
+ // XXX should func be able to return a promise???
117
196
  reduce: function(func, res){
118
197
  return this.constructor(this,
119
198
  function(e){
@@ -160,32 +239,29 @@ object.Constructor('IterablePromise', Promise, {
160
239
  .reverse(),
161
240
  'raw') },
162
241
 
163
- // NOTE: these can create an unresolved promise from a resolved
164
- // promise...
165
- // XXX EXPEREMENTAL...
166
- // ....can we remove a level of indirection here???
167
- // would be better to use the raw mode...
242
+ // NOTE: the following methods can create an unresolved promise from
243
+ // a resolved promise...
168
244
  concat: function(other){
169
- var lst = this.__list
170
- return lst instanceof Promise ?
171
- this.constructor([this, other])
172
- .flat()
173
- : other instanceof IterablePromise ?
174
- this.constructor(
175
- lst.concat(other.__list),
176
- 'raw')
245
+ var that = this
246
+ var cur = this.__pack(this)
247
+ var other = this.__pack(other)
248
+ return this.constructor(
249
+ // NOTE: we are not using only the first branch to keep the
250
+ // lists as exposed as possible thus avoiding blocking
251
+ // until the whole ting is resolved...
252
+ (cur instanceof Promise
253
+ && other instanceof Promise) ?
254
+ Promise.all([cur, other])
255
+ .then(function(list){
256
+ return list[0].concat(list[1]) })
257
+ : cur instanceof Promise ?
258
+ cur.then(function(list){
259
+ return list.concat(other) })
177
260
  : other instanceof Promise ?
178
- this.constructor(
179
- lst.concat(other
180
- .then(function(res){
181
- return res instanceof Array ?
182
- res
183
- : [res] })),
184
- 'raw')
185
- : this.constructor(
186
- // XXX this is cheating -- need a more direct way to form the array...
187
- lst.concat(this.constructor(other).__list),
188
- 'raw') },
261
+ other.then(function(list){
262
+ return cur.concat(list) })
263
+ : cur.concat(other),
264
+ 'raw') },
189
265
  push: function(elem){
190
266
  return this.concat([elem]) },
191
267
  unshift: function(elem){
@@ -196,6 +272,7 @@ object.Constructor('IterablePromise', Promise, {
196
272
  // .pop()
197
273
  // .shift()
198
274
  // .first() / .last()
275
+ // .at(..)
199
276
  // ...would be nice if these could stop everything that's not
200
277
  // needed to execute...
201
278
 
@@ -268,6 +345,26 @@ object.Constructor('IterablePromise', Promise, {
268
345
  // manually handle the stop...
269
346
  // - another issue here is that the stop would happen in order of
270
347
  // execution and not order of elements...
348
+ // XXX DOC:
349
+ // inputs:
350
+ // - Chaining -- list instanceof IterablePromise
351
+ // After all the promises resolve .flat() should
352
+ // turn this into the input list.
353
+ // For this to work we'll need to at least wrap all
354
+ // arrays and promise results in arrays.
355
+ // (currently each value is wrapped)
356
+ // -> __list
357
+ // - promise (value | array)
358
+ // - array of:
359
+ // - array
360
+ // - value
361
+ // - promise (value | array)
362
+ // - New
363
+ // - promise (value | array)
364
+ // - value (non-array)
365
+ // - array of:
366
+ // - value
367
+ // - promise (value)
271
368
  __new__: function(_, list, handler){
272
369
  // instance...
273
370
  var promise
@@ -284,47 +381,10 @@ object.Constructor('IterablePromise', Promise, {
284
381
  IterablePromise)
285
382
 
286
383
  if(promise){
287
-
288
384
  if(handler != 'raw'){
289
- handler = handler
290
- ?? function(e){
291
- return [e] }
292
-
293
- // NOTE: this is recursive to handle expanding nested promises...
294
- var handle = function(elem){
295
- // call the handler...
296
- return (elem && elem.then) ?
297
- //elem.then(function(elem){
298
- // return handler(elem) })
299
- elem.then(handler)
300
- : handler(elem) }
301
-
302
- // handle the list...
303
- // NOTE: we can't .flat() the results here as we need to
304
- // wait till all the promises resolve...
305
- list =
306
- (list instanceof IterablePromise
307
- && !(list.__list instanceof Promise)) ?
308
- // NOTE: this is essentially the same as below but
309
- // with a normalized list as input...
310
- // XXX can we merge the two???
311
- list.__list
312
- .map(function(elems){
313
- return elems instanceof Promise ?
314
- elems.then(function(elems){
315
- return elems
316
- .map(handle)
317
- .flat() })
318
- : elems
319
- .map(handle)
320
- .flat() })
321
- : list instanceof Promise ?
322
- // special case: promised list...
323
- list.then(function(list){
324
- return [list].flat()
325
- .map(handle) })
326
- : [list].flat()
327
- .map(handle) }
385
+ list = list instanceof IterablePromise ?
386
+ this.__handle(list.__list, handler)
387
+ : this.__pack(list, handler) }
328
388
 
329
389
  Object.defineProperty(obj, '__list', {
330
390
  value: list,
@@ -332,14 +392,9 @@ object.Constructor('IterablePromise', Promise, {
332
392
  })
333
393
 
334
394
  // handle promise state...
335
- ;(list instanceof Promise ?
336
- // special case: promised list...
337
- list
338
- : Promise.all([list].flat()))
339
- .then(function(res){
340
- promise.resolve(handler ?
341
- res.flat()
342
- : res) })
395
+ this.__unpack(list)
396
+ .then(function(list){
397
+ promise.resolve(list) })
343
398
  .catch(promise.reject) }
344
399
 
345
400
  return obj },
@@ -547,8 +602,8 @@ object.Mixin('PromiseProtoMixin', 'soft', {
547
602
  as: ProxyPromise,
548
603
 
549
604
  // XXX
550
- iter: function(){
551
- return IterablePromise(this) },
605
+ iter: function(handler){
606
+ return IterablePromise(this, handler) },
552
607
  })
553
608
 
554
609
  PromiseProtoMixin(Promise.prototype)
package/README.md CHANGED
@@ -1389,7 +1389,7 @@ controlled(t.then())
1389
1389
  // ...
1390
1390
  ```
1391
1391
 
1392
- Note that functionally this can be considered a special-case of an
1392
+ Note that this functionally can be considered a special-case of an
1393
1393
  [interactive promise](#interactive-promises), but in reality they are two
1394
1394
  different implementations, the main differences are:
1395
1395
  - _Cooperative promise_ constructor does not need a resolver function,
@@ -1485,8 +1485,6 @@ var p = Promise.iter([ .. ])
1485
1485
  // ...
1486
1486
  })
1487
1487
  // items reach here as soon as they are returned by the filter stage handler...
1488
- // NOTE: the filter handler may return promises, those will not be processed
1489
- // until they are resolved...
1490
1488
  .map(function(e){
1491
1489
  // ...
1492
1490
  })
@@ -1504,6 +1502,12 @@ This approach has a number of advantages:
1504
1502
  And some disadvantages:
1505
1503
  - item indexes are unknowable until all the promises resolve.
1506
1504
 
1505
+ Calling each of the `<promise-iter>` methods will return a new and unresolved
1506
+ promise, even if the original is resolved.
1507
+
1508
+ If all values are resolved the `<promise-iter>` will resolve on the next
1509
+ execution frame.
1510
+
1507
1511
  <!--
1508
1512
  XXX should we support generators as input?
1509
1513
  ...not sure about the control flow direction here, on one hand the generator
@@ -1582,19 +1586,21 @@ and [`.reduce(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe
1582
1586
 
1583
1587
  Note that these are different to `Array`'s equivalents in some details:
1584
1588
  - `<handler>` is _not_ called in the order of element occurrence but rather
1585
- in the order of elements are resolved/ready.
1589
+ in the order of elements are resolved/ready.
1586
1590
  - `<handler>` does not get either the element _index_ or the _container_.
1587
- this is because the index with _out-of-order_ and _depth-first_ execution the
1588
- index is unknowable and the container is a promise/black-box.
1591
+ this is because in _out-of-order_ and _depth-first_ execution the
1592
+ index is _unknowable_ and the container is a promise/black-box.
1589
1593
 
1590
- This is especially critical for `.reduce(..)` as iteration in an order different
1591
- from the order of elements _can_ affect actual result if this is not expected.
1594
+ This is especially critical for `.reduce(..)` as the iteration in an order
1595
+ different from the order of elements _can_ affect actual result if this is
1596
+ not expected.
1592
1597
 
1593
1598
  `.reduce(..)` is also a bit different here in that it will return a basic
1594
- `<promise>` object as we can't know what will it will reduce to.
1599
+ `<promise>` rather than an iterable promise object as we can't know what
1600
+ will it will reduce to.
1595
1601
 
1596
- Note that since `.reduce(..)` order can not be guaranteed there is no point
1597
- in implementing `.reduceRigth(..)`.
1602
+ Note that since `.reduce(..)` handler's execution order can not be known,
1603
+ there is no point in implementing `.reduceRigth(..)`.
1598
1604
 
1599
1605
 
1600
1606
  #### `<promise-iter>.flat(..)`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ig-types",
3
- "version": "6.12.0",
3
+ "version": "6.13.4",
4
4
  "description": "Generic JavaScript types and type extensions...",
5
5
  "main": "main.js",
6
6
  "scripts": {
package/test.js CHANGED
@@ -111,45 +111,160 @@ var cases = test.Cases({
111
111
  RegExp: function(assert){
112
112
  },
113
113
 
114
- Promise: function(assert){
114
+ IterablePromise: test.TestSet(function(){
115
+ var create = function(assert, value){
116
+ return {
117
+ input: value,
118
+ output: assert(Promise.iter(value), 'Promise.iter(', value, ')'),
119
+ } }
120
+
121
+ this.Setup({
122
+ empty: function(assert){
123
+ return create(assert, []) },
124
+ value: function(assert){
125
+ return create(assert, 123) },
126
+ array: function(assert){
127
+ return create(assert, [1, 2, 3]) },
128
+ nested_array: function(assert){
129
+ return create(assert, [1, 2, [3]]) },
130
+ promise_value: function(assert){
131
+ return create(assert, Promise.resolve(123)) },
132
+ promise_array: function(assert){
133
+ return create(assert, Promise.resolve([1, 2, 3])) },
134
+ promise_nested_array: function(assert){
135
+ return create(assert, Promise.resolve([1, 2, [3]])) },
136
+ array_mixed: function(assert){
137
+ return create(assert, [1, Promise.resolve(2), 3]) },
138
+ nested_array_mixed: function(assert){
139
+ return create(assert, [
140
+ 1,
141
+ Promise.resolve(2),
142
+ [3],
143
+ Promise.resolve([4]),
144
+ ]) },
145
+ promise_array_mixed: function(assert){
146
+ return create(assert, Promise.resolve([1, Promise.resolve(2), 3])) },
147
+ promise_nested_array_mixed: function(assert){
148
+ return create(assert, Promise.resolve([
149
+ 1,
150
+ Promise.resolve(2),
151
+ [3],
152
+ Promise.resolve([4]),
153
+ ])) },
154
+ })
155
+ this.Modifier({
156
+ nest: function(assert, setup){
157
+ setup.output = Promise.iter(setup.output)
158
+ return setup },
159
+ iter: function(assert, setup){
160
+ setup.output = setup.output.iter()
161
+ return setup },
162
+
163
+ map_asis: function(assert, setup){
164
+ setup.output = setup.output
165
+ .map(function(e){
166
+ return e })
167
+ return setup },
168
+ map_promise: function(assert, setup){
169
+ setup.output = setup.output
170
+ .map(function(e){
171
+ return Promise.resolve(e) })
172
+ return setup },
173
+
174
+ filter_all: function(assert, setup){
175
+ setup.output = setup.output
176
+ .filter(function(e){ return true })
177
+ return setup },
178
+ // XXX either the test is worng or something is broken...
179
+ filter_none: function(assert, setup){
180
+ return {
181
+ input: [],
182
+ output: setup.output
183
+ .filter(function(e){ return false }),
184
+ } },
185
+
186
+ /* XXX need tuning...
187
+ concat_basic: function(assert, {input, output}){
188
+ return {
189
+ input: [input].flat()
190
+ .concat(['a', 'b', 'c']),
191
+ output: output
192
+ .concat(['a', 'b', 'c']),
193
+ } },
194
+ concat_nested_array: function(assert, {input, output}){
195
+ return {
196
+ input: [input].flat()
197
+ .concat(['a', ['b'], 'c']),
198
+ output: output
199
+ .concat(['a', ['b'], 'c']),
200
+ } },
201
+ //*/
202
+
203
+ })
204
+ this.Test({
205
+ value: async function(assert, {input, output}){
206
+
207
+ var res = await output
208
+
209
+ assert(res instanceof Array, 'result is array')
210
+
211
+ input instanceof Array ?
212
+ // XXX this does not catch some errors -- map_promise specifically...
213
+ assert.array(res,
214
+ await Promise.all(input),
215
+ 'array -> array')
216
+ : (input instanceof Promise && await input instanceof Array) ?
217
+ assert.array(res,
218
+ await input,
219
+ 'promise array -> array')
220
+ : input instanceof Promise ?
221
+ assert.array(res,
222
+ [await input],
223
+ 'promise value -> array')
224
+ : assert.array(res,
225
+ [input],
226
+ 'value -> array') },
227
+ })
228
+ }),
229
+ Promise: async function(assert){
115
230
  var p = assert(Promise.cooperative(), '.cooperative()')
116
- //var p = assert(promise._CooperativePromise())
117
231
 
118
- assert(!p.isSet, '.isSet is false')
119
-
232
+ assert(!p.isSet, 'promise unset')
233
+
120
234
  var RESOLVE = 123
235
+ var then = false
236
+ var done = false
121
237
 
122
- var then
123
238
  p.then(function(v){
124
- // XXX this does not get printed for some reason...
125
- console.log('!!!!!!!!!!! then')
126
- // XXX this seems not to work/print/count a fail...
127
- assert(false, 'test fail')
128
-
129
- then = v })
239
+ then = assert(v == RESOLVE, '.then(..) handled') })
130
240
 
131
- assert(!p.isSet, '.isSet is false')
132
-
133
- var fin
134
241
  p.finally(function(){
135
- fin = true })
242
+ done = assert(true, '.finally(..) handled') })
136
243
 
137
- assert(!p.isSet, '.isSet is false')
244
+ assert(!p.isSet, 'promise unset')
138
245
 
139
246
  p.set(RESOLVE)
140
247
 
141
- assert(p.isSet, '.isSet')
142
-
143
- // XXX without setTimeout(..) these are run before the
144
- // .then(..) / .finally(..) have a chance to run...
145
- // ...not yet sure how I feel about this...
146
- // XXX with setTimeout(..) these appear not to have ANY effect,
147
- // as if setTimeout(..) did not run...
148
- setTimeout(function(){
149
- assert(false, 'test fail')
150
- assert(then == RESOLVE, '.then(..)')
151
- assert(fin, '.finally(..)')
152
- }, 0)
248
+ assert(p.isSet, 'promise set')
249
+
250
+ // allow the promise to finalize...
251
+ await p
252
+
253
+ assert(then, '.then(..): confirmed')
254
+ assert(done, '.done(..): confirmed')
255
+
256
+ // XXX
257
+
258
+ assert(await Promise.iter([1, Promise.resolve(2), [3]]), '.iter(..)')
259
+
260
+ assert.array(
261
+ await Promise.iter([1, 2, 3]),
262
+ [1, 2, 3],
263
+ 'basic array')
264
+ assert.array(
265
+ await Promise.iter([1, Promise.resolve(2), 3]),
266
+ [1, 2, 3],
267
+ 'promises as elements')
153
268
  },
154
269
 
155
270
  // Date.js