ig-types 6.11.3 → 6.13.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.
Files changed (4) hide show
  1. package/Promise.js +125 -60
  2. package/README.md +75 -28
  3. package/package.json +1 -1
  4. package/test.js +126 -28
package/Promise.js CHANGED
@@ -65,6 +65,62 @@ object.Constructor('IterablePromise', Promise, {
65
65
  //
66
66
  __list: null,
67
67
 
68
+ // low-level .__list handlers/helpers...
69
+ // NOTE: these can be useful for debugging and extending...
70
+ __normalize: function(list, handler){
71
+ // handle promise list...
72
+ if(list instanceof Promise){
73
+ var that = this
74
+ return list.then(function(list){
75
+ return that.__normalize(list, handler) }) }
76
+
77
+ var handle = !!handler
78
+ handler = handler
79
+ ?? function(elem){
80
+ return [elem] }
81
+ return [list].flat()
82
+ .map(function(elem){
83
+ return elem instanceof Array ?
84
+ handler(elem)
85
+ : elem && elem.then ?
86
+ elem.then(handler)
87
+ : !handle ?
88
+ elem
89
+ : handler(elem) }) },
90
+ __handle: function(list, handler){
91
+ var that = this
92
+ if(typeof(list) == 'function'){
93
+ handler = list
94
+ list = this.__list }
95
+ if(!handler){
96
+ return list }
97
+ // handle promise list...
98
+ if(list instanceof Promise){
99
+ return list.then(function(list){
100
+ return that.__handle(list, handler) }) }
101
+
102
+ return list.map(function(elem){
103
+ return elem instanceof Array ?
104
+ that.__normalize(elem, handler)
105
+ : elem instanceof Promise ?
106
+ that.__normalize([elem], handler).pop()
107
+ .then(function(elem){
108
+ return elem.flat() })
109
+ : handler(elem) })
110
+ .flat() },
111
+ __denormalize: function(list){
112
+ list = list
113
+ ?? this.__list
114
+ // handle promise list...
115
+ if(list instanceof Promise){
116
+ var that = this
117
+ return list.then(function(list){
118
+ return that.__denormalize(list) }) }
119
+
120
+ return Promise.all(list)
121
+ .then(function(list){
122
+ return list.flat() }) },
123
+
68
124
 
69
125
  // iterator methods...
70
126
  //
@@ -99,21 +155,36 @@ object.Constructor('IterablePromise', Promise, {
99
155
  map: function(func){
100
156
  return this.constructor(this,
101
157
  function(e){
102
- return [func(e)] }) },
158
+ //return [func(e)] }) },
159
+ var res = func(e)
160
+ return res instanceof Promise ?
161
+ res.then(function(e){
162
+ return [e] })
163
+ : [res] }) },
103
164
  filter: function(func){
104
165
  return this.constructor(this,
105
166
  function(e){
106
- return func(e) ?
107
- [e]
167
+ //return func(e) ?
168
+ // [e]
169
+ // : [] }) },
170
+ var res = func(e)
171
+ return res instanceof Promise ?
172
+ res.then(function(res){
173
+ return res ?
174
+ [e]
175
+ : [] })
176
+ : res ?
177
+ [e]
108
178
  : [] }) },
109
179
  // NOTE: this does not return an iterable promise as we can't know
110
180
  // what the user reduces to...
111
181
  // XXX we could look at the initial state though...
112
182
  // NOTE: the items can be handled out of order because the nested
113
183
  // promises can resolve in any order.
114
- // XXX write how to go around this...
184
+ // XXX doc how to go around this...
115
185
  // NOTE: since order of execution can not be guaranteed there is no
116
186
  // point in implementing .reduceRight(..)
187
+ // XXX should func be able to return a promise???
117
188
  reduce: function(func, res){
118
189
  return this.constructor(this,
119
190
  function(e){
@@ -121,6 +192,14 @@ object.Constructor('IterablePromise', Promise, {
121
192
  return [] })
122
193
  .then(function(){
123
194
  return res }) },
195
+ /* // XXX since order of execution is not fixed there is no point in
196
+ // adding this.
197
+ reduceRight: function(func, res){
198
+ return this
199
+ .reverse()
200
+ .reduce(...arguments)
201
+ .reverse() },
202
+ //*/
124
203
  flat: function(depth=1){
125
204
  return this.constructor(this,
126
205
  function(e){
@@ -152,18 +231,26 @@ object.Constructor('IterablePromise', Promise, {
152
231
  .reverse(),
153
232
  'raw') },
154
233
 
234
+ // NOTE: these can create an unresolved promise from a resolved
235
+ // promise...
236
+ concat: function(other){
237
+ return this.constructor(
238
+ this.__list
239
+ .concat(this.__normalize(other)),
240
+ 'raw') },
241
+ push: function(elem){
242
+ return this.concat([elem]) },
243
+ unshift: function(elem){
244
+ return this.constructor([elem])
245
+ .concat(this) },
246
+
155
247
  // XXX do we need these?
156
248
  // .pop()
157
249
  // .shift()
158
250
  // .first() / .last()
159
- // XXX these can change the "resolved" state...
160
- // ...i.e. return a pending promise when called from a fulfilled
161
- // promise....
162
- // .concat(..)
163
- // .push(..)
164
- // .unshift(..)
165
- // .first(..) / .last(..)
166
-
251
+ // ...would be nice if these could stop everything that's not
252
+ // needed to execute...
253
+
167
254
 
168
255
  // Overload .then(..), .catch(..) and .finally(..) to return a plain
169
256
  // Promise instnace...
@@ -233,6 +320,26 @@ object.Constructor('IterablePromise', Promise, {
233
320
  // manually handle the stop...
234
321
  // - another issue here is that the stop would happen in order of
235
322
  // execution and not order of elements...
323
+ // XXX DOC:
324
+ // inputs:
325
+ // - Chaining -- list instanceof IterablePromise
326
+ // After all the promises resolve .flat() should
327
+ // turn this into the input list.
328
+ // For this to work we'll need to at least wrap all
329
+ // arrays and promise results in arrays.
330
+ // (currently each value is wrapped)
331
+ // -> __list
332
+ // - promise (value | array)
333
+ // - array of:
334
+ // - array
335
+ // - value
336
+ // - promise (value | array)
337
+ // - New
338
+ // - promise (value | array)
339
+ // - value (non-array)
340
+ // - array of:
341
+ // - value
342
+ // - promise (value)
236
343
  __new__: function(_, list, handler){
237
344
  // instance...
238
345
  var promise
@@ -249,47 +356,10 @@ object.Constructor('IterablePromise', Promise, {
249
356
  IterablePromise)
250
357
 
251
358
  if(promise){
252
-
253
359
  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) }
360
+ list = list instanceof IterablePromise ?
361
+ this.__handle(list.__list, handler)
362
+ : this.__normalize(list, handler) }
293
363
 
294
364
  Object.defineProperty(obj, '__list', {
295
365
  value: list,
@@ -297,14 +367,9 @@ object.Constructor('IterablePromise', Promise, {
297
367
  })
298
368
 
299
369
  // handle promise state...
300
- ;(list instanceof Promise ?
301
- // special case: promised list...
302
- list
303
- : Promise.all([list].flat()))
304
- .then(function(res){
305
- promise.resolve(handler ?
306
- res.flat()
307
- : res) })
370
+ this.__denormalize(list)
371
+ .then(function(list){
372
+ promise.resolve(list) })
308
373
  .catch(promise.reject) }
309
374
 
310
375
  return obj },
package/README.md CHANGED
@@ -75,6 +75,8 @@ Library of JavaScript type extensions, types and utilities.
75
75
  - [`<promise-iter>.map(..)` / `<promise-iter>.filter(..)` / `<promise-iter>.reduce(..)`](#promise-itermap--promise-iterfilter--promise-iterreduce)
76
76
  - [`<promise-iter>.flat(..)`](#promise-iterflat)
77
77
  - [`<promise-iter>.reverse()`](#promise-iterreverse)
78
+ - [`<promise-iter>.concat(..)`](#promise-iterconcat)
79
+ - [`<promise-iter>.push(..)` / `<promise-iter>.unshift(..)`](#promise-iterpush--promise-iterunshift)
78
80
  - [`<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally)
79
81
  - [Advanced handler](#advanced-handler)
80
82
  - [Promise proxies](#promise-proxies)
@@ -1387,7 +1389,7 @@ controlled(t.then())
1387
1389
  // ...
1388
1390
  ```
1389
1391
 
1390
- 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
1391
1393
  [interactive promise](#interactive-promises), but in reality they are two
1392
1394
  different implementations, the main differences are:
1393
1395
  - _Cooperative promise_ constructor does not need a resolver function,
@@ -1483,8 +1485,6 @@ var p = Promise.iter([ .. ])
1483
1485
  // ...
1484
1486
  })
1485
1487
  // items reach here as soon as they are returned by the filter stage handler...
1486
- // NOTE: the filter handler may return promises, those will not be processed
1487
- // until they are resolved...
1488
1488
  .map(function(e){
1489
1489
  // ...
1490
1490
  })
@@ -1502,6 +1502,12 @@ This approach has a number of advantages:
1502
1502
  And some disadvantages:
1503
1503
  - item indexes are unknowable until all the promises resolve.
1504
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
+
1505
1511
  <!--
1506
1512
  XXX should we support generators as input?
1507
1513
  ...not sure about the control flow direction here, on one hand the generator
@@ -1580,19 +1586,21 @@ and [`.reduce(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe
1580
1586
 
1581
1587
  Note that these are different to `Array`'s equivalents in some details:
1582
1588
  - `<handler>` is _not_ called in the order of element occurrence but rather
1583
- in the order of elements are resolved/ready.
1589
+ in the order of elements are resolved/ready.
1584
1590
  - `<handler>` does not get either the element _index_ or the _container_.
1585
- this is because the index with _out-of-order_ and _depth-first_ execution the
1586
- 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.
1587
1593
 
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.
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.
1590
1597
 
1591
1598
  `.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.
1599
+ `<promise>` rather than an iterable promise object as we can't know what
1600
+ will it will reduce to.
1593
1601
 
1594
- Note that since `.reduce(..)` order can not be guaranteed there is no point
1595
- in implementing `.reduceRigth(..)`.
1602
+ Note that since `.reduce(..)` handler's execution order can not be known,
1603
+ there is no point in implementing `.reduceRigth(..)`.
1596
1604
 
1597
1605
 
1598
1606
  #### `<promise-iter>.flat(..)`
@@ -1613,7 +1621,35 @@ This is similar to [`<array>.flat(..)`](https://developer.mozilla.org/en-US/docs
1613
1621
  -> <promise-iter>
1614
1622
  ```
1615
1623
 
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.
1624
+ This is deferent from `<array>.reverse()` in that it will _not_ reverse in-place,
1625
+ but rather a _reversed copy_ will be created.
1626
+
1627
+ 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.
1628
+
1629
+
1630
+ #### `<promise-iter>.concat(..)`
1631
+
1632
+ ```bnf
1633
+ <promise-iter>.concat(<other>)
1634
+ -> <promise-iter>
1635
+ ```
1636
+
1637
+ This is similar to [`<array>.concat(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) see it for more info.
1638
+
1639
+
1640
+ #### `<promise-iter>.push(..)` / `<promise-iter>.unshift(..)`
1641
+
1642
+ ```bnf
1643
+ <promise-iter>.push(<elem>)
1644
+ -> <promise-iter>
1645
+
1646
+ <promise-iter>.unshift(<elem>)
1647
+ -> <promise-iter>
1648
+ ```
1649
+
1650
+ These are similar to [`<array>.push(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push)
1651
+ and [`<array>.unshift(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift)
1652
+ see them for more info.
1617
1653
 
1618
1654
 
1619
1655
  #### `<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`
@@ -1633,40 +1669,51 @@ can be useful to hide the extended promise API from further code.
1633
1669
  #### Advanced handler
1634
1670
 
1635
1671
  ```bnf
1636
- Promise.iter(<block-array>, <handler>)
1672
+ Promise.iter(<block>, <handler>)
1637
1673
  -> <iterable-promise>
1674
+ ```
1638
1675
 
1639
- <handler>(<elem>)
1640
- -> [ <elems> ]
1676
+ The `<handler>` will get passed each resolved `<value>` of the input `<block>`
1677
+ as soon as it's available/resolved.
1678
+
1679
+ The `<handler>` return value is unwrapped into the resulting array, allowing
1680
+ each call to both remove elements (i.e. returning `[]`) from the resulting
1681
+ `<block>` as well as insert multiple items (by returning an array of items).
1682
+
1683
+ <!-- XXX returning promises from handler needs to be documented/tested... -->
1684
+
1685
+ ```bnf
1686
+ <handler>(<value>)
1687
+ -> []
1688
+ -> [ <elem>, .. ]
1689
+ -> <non-array>
1641
1690
  ```
1642
1691
 
1643
1692
  ```bnf
1644
- <block-array> ::=
1693
+ <block> ::=
1645
1694
  []
1646
- | [ <block-elem>, .. ]
1695
+ | [ <elem>, .. ]
1647
1696
 
1648
- <block-elem> ::=
1649
- []
1650
- | [ <value>, .. ]
1651
- | <promise>
1652
- | <non-array>
1697
+ <elem> ::=
1698
+ <value>
1699
+ | <promise>(<value>)
1653
1700
  ```
1654
1701
 
1655
1702
  Example:
1656
1703
  ```javascript
1657
1704
  var p = Promise.iter(
1658
- // NOTE: if you want an element to explicitly be an array wrap it in
1659
- // an array -- like the last element here...
1660
- [[1, 2], 3, Promise.resolve(4), [[5, 6]]],
1705
+ [1, 2, 3, Promise.resolve(4), [5, 6]],
1661
1706
  function(elem){
1707
+ // duplicate even numbers...
1662
1708
  return elem % 2 == 0 ?
1663
1709
  [elem, elem]
1710
+ // return arrays as-is...
1664
1711
  : elem instanceof Array ?
1665
- [elem]
1712
+ [elem]
1713
+ // remove other elements...
1666
1714
  : [] })
1667
1715
  .then(function(lst){
1668
- console.log(lst) // -> [2, 2, 4, 4, [5, 6]]
1669
- })
1716
+ console.log(lst) }) // -> [2, 2, 4, 4, [5, 6]]
1670
1717
  ```
1671
1718
 
1672
1719
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ig-types",
3
- "version": "6.11.3",
3
+ "version": "6.13.2",
4
4
  "description": "Generic JavaScript types and type extensions...",
5
5
  "main": "main.js",
6
6
  "scripts": {
package/test.js CHANGED
@@ -111,45 +111,143 @@ 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
+ })
187
+ this.Test({
188
+ value: async function(assert, {input, output}){
189
+
190
+ var res = await output
191
+
192
+ assert(res instanceof Array, 'result is array')
193
+
194
+ input instanceof Array ?
195
+ // XXX this does not catch some errors -- map_promise specifically...
196
+ assert.array(res,
197
+ await Promise.all(input),
198
+ 'array -> array')
199
+ : (input instanceof Promise && await input instanceof Array) ?
200
+ assert.array(res,
201
+ await input,
202
+ 'promise array -> array')
203
+ : input instanceof Promise ?
204
+ assert.array(res,
205
+ [await input],
206
+ 'promise value -> array')
207
+ : assert.array(res,
208
+ [input],
209
+ 'value -> array') },
210
+ })
211
+ }),
212
+ Promise: async function(assert){
115
213
  var p = assert(Promise.cooperative(), '.cooperative()')
116
- //var p = assert(promise._CooperativePromise())
117
214
 
118
- assert(!p.isSet, '.isSet is false')
119
-
215
+ assert(!p.isSet, 'promise unset')
216
+
120
217
  var RESOLVE = 123
218
+ var then = false
219
+ var done = false
121
220
 
122
- var then
123
221
  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 })
222
+ then = assert(v == RESOLVE, '.then(..) handled') })
130
223
 
131
- assert(!p.isSet, '.isSet is false')
132
-
133
- var fin
134
224
  p.finally(function(){
135
- fin = true })
225
+ done = assert(true, '.finally(..) handled') })
136
226
 
137
- assert(!p.isSet, '.isSet is false')
227
+ assert(!p.isSet, 'promise unset')
138
228
 
139
229
  p.set(RESOLVE)
140
230
 
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)
231
+ assert(p.isSet, 'promise set')
232
+
233
+ // allow the promise to finalize...
234
+ await p
235
+
236
+ assert(then, '.then(..): confirmed')
237
+ assert(done, '.done(..): confirmed')
238
+
239
+ // XXX
240
+
241
+ assert(await Promise.iter([1, Promise.resolve(2), [3]]), '.iter(..)')
242
+
243
+ assert.array(
244
+ await Promise.iter([1, 2, 3]),
245
+ [1, 2, 3],
246
+ 'basic array')
247
+ assert.array(
248
+ await Promise.iter([1, Promise.resolve(2), 3]),
249
+ [1, 2, 3],
250
+ 'promises as elements')
153
251
  },
154
252
 
155
253
  // Date.js