ig-types 6.15.0 → 6.16.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.
package/Array.js CHANGED
@@ -12,6 +12,7 @@
12
12
  /*********************************************************************/
13
13
 
14
14
  var object = require('ig-object')
15
+ var stoppable = require('ig-stoppable')
15
16
 
16
17
  var generator = require('./generator')
17
18
 
@@ -22,8 +23,7 @@ var generator = require('./generator')
22
23
  // NOTE: this is used in a similar fashion to Python's StopIteration...
23
24
  var STOP =
24
25
  module.STOP =
25
- object.STOP
26
-
26
+ stoppable.STOP
27
27
 
28
28
 
29
29
  //---------------------------------------------------------------------
@@ -212,8 +212,12 @@ object.Mixin('ArrayMixin', 'soft', {
212
212
  // done...
213
213
  : [] },
214
214
 
215
- iter: function*(lst=[]){
216
- yield* lst.iter() },
215
+ // XXX not sure about the handler API here yet...
216
+ iter: function*(lst=[], handler=undefined){
217
+ yield* lst.iter(
218
+ ...(handler ?
219
+ [handler]
220
+ : [])) },
217
221
  })
218
222
 
219
223
 
@@ -488,8 +492,22 @@ object.Mixin('ArrayProtoMixin', 'soft', {
488
492
  // -> iterator
489
493
  //
490
494
  // XXX should this take an argument and be like map??
491
- iter: function*(){
492
- yield* this },
495
+ // XXX this should handle throwing STOP!!!
496
+ // ...might also ne a good idea to isolate the STOP mechanics
497
+ // into a spearate module/package...
498
+ iter: stoppable(function*(handler=undefined){
499
+ if(handler){
500
+ var i = 0
501
+ for(var e of this){
502
+ var res = handler.call(this, e, i++)
503
+ // treat non-iterables as single elements...
504
+ if(typeof(res) == 'object'
505
+ && Symbol.iterator in res){
506
+ yield* res
507
+ } else {
508
+ yield res } }
509
+ } else {
510
+ yield* this }}),
493
511
 
494
512
 
495
513
  // Stoppable iteration...
package/Function.js ADDED
@@ -0,0 +1,18 @@
1
+ /**********************************************************************
2
+ *
3
+ *
4
+ *
5
+ **********************************************/ /* c8 ignore next 2 */
6
+ ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
7
+ (function(require){ var module={} // make module AMD/node compatible...
8
+ /*********************************************************************/
9
+
10
+
11
+ var AsyncFunction =
12
+ module.AsyncFunction =
13
+ (async function(){}).constructor
14
+
15
+
16
+
17
+ /**********************************************************************
18
+ * vim:set ts=4 sw=4 : */ return module })
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.
@@ -31,6 +30,8 @@
31
30
 
32
31
  var object = require('ig-object')
33
32
 
33
+ //var generator = require('./generator')
34
+
34
35
 
35
36
 
36
37
  //---------------------------------------------------------------------
@@ -39,16 +40,6 @@ var object = require('ig-object')
39
40
  // Like Promise.all(..) but adds ability to iterate through results
40
41
  // via generators .map(..)/.reduce(..) and friends...
41
42
  //
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 EXPEREMENTAL: STOP...
52
43
  // NOTE: the following can not be implemented here:
53
44
  // .splice(..) - can't both modify and return
54
45
  // a result...
@@ -68,18 +59,19 @@ var object = require('ig-object')
68
59
  // back to the complex IterablePromise...
69
60
  //
70
61
  // XXX how do we handle errors/rejections???
62
+ // ...mostly the current state is OK, but need more testing...
63
+ // XXX add support for async generators...
71
64
  //
72
65
 
73
- // XXX should these be exported???
74
66
  var iterPromiseProxy =
75
- //module.iterPromiseProxy =
67
+ module.iterPromiseProxy =
76
68
  function(name){
77
69
  return function(...args){
78
70
  return this.constructor(
79
71
  this.then(function(lst){
80
72
  return lst[name](...args) })) } }
81
73
  var promiseProxy =
82
- //module.promiseProxy =
74
+ module.promiseProxy =
83
75
  function(name){
84
76
  return async function(...args){
85
77
  return (await this)[name](...args) } }
@@ -87,7 +79,6 @@ function(name){
87
79
  var IterablePromise =
88
80
  module.IterablePromise =
89
81
  object.Constructor('IterablePromise', Promise, {
90
- // XXX EXPEREMENTAL: STOP...
91
82
  get STOP(){
92
83
  return Array.STOP },
93
84
 
@@ -129,6 +120,11 @@ object.Constructor('IterablePromise', Promise, {
129
120
  // stop will stop the handlers not yet run and not the next
130
121
  // handlers in sequence.
131
122
  // XXX EXPEREMENTAL: STOP...
123
+ // XXX add support for async generators...
124
+ // ...an async generator is not "parallel", i.e. intil one
125
+ // returned promise is resolved the generator blocks (will not
126
+ // advance)...
127
+ // ...can we feed out a results one by one???
132
128
  __pack: function(list, handler=undefined){
133
129
  var that = this
134
130
  // handle iterable promise list...
@@ -237,8 +233,9 @@ object.Constructor('IterablePromise', Promise, {
237
233
  that.__pack(elem, handler)
238
234
  : elem instanceof Promise ?
239
235
  that.__pack(elem, handler)
240
- .then(function(elem){
241
- return elem.flat() })
236
+ //.then(function(elem){
237
+ .then(function([elem]){
238
+ return elem })
242
239
  : [handler(elem)] })
243
240
  .flat() },
244
241
  // unpack array (async)...
@@ -297,6 +294,8 @@ object.Constructor('IterablePromise', Promise, {
297
294
  .then(function(){
298
295
  return res }) },
299
296
 
297
+ // XXX .chain(..) -- see generator.chain(..)
298
+
300
299
  flat: function(depth=1){
301
300
  return this.constructor(this,
302
301
  function(e){
@@ -367,6 +366,7 @@ object.Constructor('IterablePromise', Promise, {
367
366
  var list = this.__packed
368
367
  return ((i != 0 && i != -1)
369
368
  || list instanceof Promise
369
+ // XXX not sure if this is correct...
370
370
  || list.at(i) instanceof Promise) ?
371
371
  (await this).at(i)
372
372
  // NOTE: we can only reason about first/last explicit elements,
@@ -384,7 +384,6 @@ object.Constructor('IterablePromise', Promise, {
384
384
  // NOTE: unlike .reduce(..) this needs the parent fully resolved
385
385
  // to be able to iterate from the end.
386
386
  // XXX is it faster to do .reverse().reduce(..) ???
387
- // XXX ???
388
387
  reduceRight: promiseProxy('reduceRight'),
389
388
 
390
389
  // NOTE: there is no way we can do a sync generator returning
@@ -465,6 +464,17 @@ object.Constructor('IterablePromise', Promise, {
465
464
  every: promiseProxy('every'),
466
465
 
467
466
 
467
+ join: async function(){
468
+ return [...(await this)]
469
+ .join(...arguments) },
470
+
471
+
472
+ // this is defined globally as Promise.prototype.iter(..)
473
+ //
474
+ // for details see: PromiseMixin(..) below...
475
+ //iter: function(handler=undefined){ ... },
476
+
477
+
468
478
  // promise api...
469
479
  //
470
480
  // Overload .then(..), .catch(..) and .finally(..) to return a plain
@@ -492,12 +502,6 @@ object.Constructor('IterablePromise', Promise, {
492
502
  : p },
493
503
 
494
504
 
495
- // this is defined globally as Promise.prototype.iter(.,)
496
- //
497
- // for details see: PromiseMixin(..) below...
498
- //iter: function(handler=undefined){ ... },
499
-
500
-
501
505
  // constructor...
502
506
  //
503
507
  // Promise.iter([ .. ])
@@ -518,6 +522,7 @@ object.Constructor('IterablePromise', Promise, {
518
522
  // items...
519
523
  // XXX we can make the index a promise, then if the client needs
520
524
  // the value they can wait for it...
525
+ // ...this may be quite an overhead...
521
526
  //
522
527
  //
523
528
  // Special cases useful for extending this constructor...
@@ -654,6 +659,7 @@ object.Constructor('InteractivePromise', Promise, {
654
659
  // Cooperative promise...
655
660
  //
656
661
  // A promise that can be resolved/rejected externally.
662
+ //
657
663
  // NOTE: normally this has no internal resolver logic...
658
664
  //
659
665
 
package/README.md CHANGED
@@ -13,6 +13,8 @@ Library of JavaScript type extensions, types and utilities.
13
13
  - [`Object.matchPartial(..)`](#objectmatchpartial)
14
14
  - [`<object>.run(..)`](#objectrun)
15
15
  - [`Object.sort(..)`](#objectsort)
16
+ - [`Function`](#function)
17
+ - [`func.AsyncFunction`](#funcasyncfunction)
16
18
  - [`Array`](#array)
17
19
  - [`<array>.first(..)` / `<array>.last(..)`](#arrayfirst--arraylast)
18
20
  - [`<array>.rol(..)`](#arrayrol)
@@ -94,7 +96,7 @@ Library of JavaScript type extensions, types and utilities.
94
96
  - [`generator.iter(..)`](#generatoriter)
95
97
  - [`generator.STOP`](#generatorstop)
96
98
  - [Generator instance iteration](#generator-instance-iteration)
97
- - [`<generator>.iter()`](#generatoriter-1)
99
+ - [`<generator>.iter(..)`](#generatoriter-1)
98
100
  - [`<generator>.map(..)` / `<generator>.filter(..)`](#generatormap--generatorfilter)
99
101
  - [`<generator>.reduce(..)` / `<generator>.greduce(..)`](#generatorreduce--generatorgreduce)
100
102
  - [`<generator>.slice(..)`](#generatorslice)
@@ -102,7 +104,6 @@ Library of JavaScript type extensions, types and utilities.
102
104
  - [`<generator>.flat(..)`](#generatorflat)
103
105
  - [`<generator>.shift()` / `<generator>.pop()` / `<generator>.gshift()` / `<generator>.gpop()`](#generatorshift--generatorpop--generatorgshift--generatorgpop)
104
106
  - [`<generator>.unshift(..)` / `<generator>.push(..)`](#generatorunshift--generatorpush)
105
- - [`<generator>.promise()`](#generatorpromise)
106
107
  - [`<generator>.then(..)` / `<generator>.catch(..)` / `<generator>.finally(..)`](#generatorthen--generatorcatch--generatorfinally)
107
108
  - [`<generator>.toArray()`](#generatortoarray)
108
109
  - [Treating iterators the same as generators](#treating-iterators-the-same-as-generators)
@@ -124,6 +125,15 @@ Library of JavaScript type extensions, types and utilities.
124
125
  - [`generator.produce(..)`](#generatorproduce)
125
126
  - [Generator helpers](#generator-helpers)
126
127
  - [`generator.stoppable(..)`](#generatorstoppable)
128
+ - [Async generator extensions](#async-generator-extensions)
129
+ - [`generator.AsyncGenerator`](#generatorasyncgenerator)
130
+ - [`<async-generator>.then(..)` / `<async-generator>.catch(..)` / `<async-generator>.finally(..)`](#async-generatorthen--async-generatorcatch--async-generatorfinally)
131
+ - [`<async-generator>.iter(..)`](#async-generatoriter)
132
+ - [`<async-generator>.map(..)` / `<async-generator>.filter(..)` / `<async-generator>.reduce(..)`](#async-generatormap--async-generatorfilter--async-generatorreduce)
133
+ - [`<async-generator>.chain(..)`](#async-generatorchain)
134
+ - [`<async-generator>.flat(..)`](#async-generatorflat)
135
+ - [`<async-generator>.concat(..)`](#async-generatorconcat)
136
+ - [`<async-generator>.push(..)` / `<async-generator>.unshift(..)`](#async-generatorpush--async-generatorunshift)
127
137
  - [Containers](#containers)
128
138
  - [`containers.UniqueKeyMap()` (`Map`)](#containersuniquekeymap-map)
129
139
  - [`<unique-key-map>.set(..)`](#unique-key-mapset)
@@ -446,6 +456,30 @@ Object.keys(Object.sort(o, ['x', 'a', '100']))
446
456
  This is similar to [`<map>.sort(..)`](#mapsort) and [`<ser>.sort(..)`](#setsort).
447
457
 
448
458
 
459
+ ## `Function`
460
+
461
+ ```javascript
462
+ var func = require('ig-types/Function')
463
+ ```
464
+
465
+ ### `func.AsyncFunction`
466
+
467
+ The async function constructor.
468
+
469
+ This enables us to test if an object is an instance of an async function.
470
+
471
+ ```javascript
472
+ var a = async function(){
473
+ // ...
474
+ }
475
+
476
+ a instanceof func.AsyncFunction // -> true
477
+ ```
478
+
479
+ This is hidden by JavaScript by default.
480
+
481
+
482
+
449
483
  ## `Array`
450
484
 
451
485
  ```javascript
@@ -2023,7 +2057,7 @@ Chained generators handle items depth-first, i.e. the items are passed as they
2023
2057
  are yielded down the generator chain.
2024
2058
 
2025
2059
 
2026
- #### `<generator>.iter()`
2060
+ #### `<generator>.iter(..)`
2027
2061
 
2028
2062
  Iterate over the generator.
2029
2063
  ```bnf
@@ -2031,7 +2065,24 @@ Iterate over the generator.
2031
2065
  -> <generator>
2032
2066
  ```
2033
2067
 
2034
- This is here mainly for compatibility with [`<array>`'s `.iter()`](#arrayiter--arrayiter).
2068
+ XXX move this to `generator.iter(..)`
2069
+
2070
+ Compatible with [`<array>`'s `.iter()`](#arrayiter--arrayiter).
2071
+
2072
+ `.iter(..)` also supports a handler function
2073
+ ```bnf
2074
+ <generator>.iter(<handler>)
2075
+ -> <generator>
2076
+
2077
+
2078
+ <handler>(<elem>, <index>)
2079
+ -> <elem>
2080
+ -> [<elem>, ..]
2081
+ -> []
2082
+ ```
2083
+
2084
+ Note that the iterables returned by `<handler>(..)` will be expanded, to prevent
2085
+ this wrap them in an array.
2035
2086
 
2036
2087
 
2037
2088
  #### `<generator>.map(..)` / `<generator>.filter(..)`
@@ -2156,30 +2207,29 @@ Value added by `.unshift(..)` will be yielded by `<generator>` "first", i.e. on
2156
2207
  _next_ call to `.next()`, regardless of the current generator state.
2157
2208
 
2158
2209
 
2159
- #### `<generator>.promise()`
2210
+ #### `<generator>.then(..)` / `<generator>.catch(..)` / `<generator>.finally(..)`
2211
+
2212
+ Return a promise and resolve it with the generator value.
2160
2213
 
2161
2214
  ```bnf
2162
- <generator>.promise()
2215
+ <generator>.then()
2163
2216
  -> <promise>
2164
2217
  ```
2165
- Return a promise and resolve it with the generator value.
2166
-
2167
- Note that this will deplete the generator.
2168
2218
 
2169
-
2170
- #### `<generator>.then(..)` / `<generator>.catch(..)` / `<generator>.finally(..)`
2219
+ Adding handlers to the promise
2171
2220
 
2172
2221
  ```bnf
2173
2222
  <generator>.then(<resolve>, <reject>)
2174
2223
  -> <promise>
2175
2224
 
2176
- <generator>.then(<reject>)
2225
+ <generator>.then(<resolve>)
2177
2226
  -> <promise>
2178
2227
 
2179
2228
  <generator>.finally(<handler>)
2180
2229
  -> <promise>
2181
2230
  ```
2182
- Shorthands to `<generator>.promise().then(..)` / `<generator>.promise().catch(..)` / `<generator>.promise().finally(..)`
2231
+
2232
+ Note that this will deplete the generator.
2183
2233
 
2184
2234
  These are the same as equivalent `Promise` methods, for more info see:
2185
2235
  https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
@@ -2483,6 +2533,26 @@ stoppable(<generator>)
2483
2533
 
2484
2534
  <!-- XXX example? -->
2485
2535
 
2536
+ ## Async generator extensions
2537
+
2538
+ XXX EXPERIMENTAL
2539
+
2540
+ #### `generator.AsyncGenerator`
2541
+
2542
+ #### `<async-generator>.then(..)` / `<async-generator>.catch(..)` / `<async-generator>.finally(..)`
2543
+
2544
+ #### `<async-generator>.iter(..)`
2545
+
2546
+ #### `<async-generator>.map(..)` / `<async-generator>.filter(..)` / `<async-generator>.reduce(..)`
2547
+
2548
+ #### `<async-generator>.chain(..)`
2549
+
2550
+ #### `<async-generator>.flat(..)`
2551
+
2552
+ #### `<async-generator>.concat(..)`
2553
+
2554
+ #### `<async-generator>.push(..)` / `<async-generator>.unshift(..)`
2555
+
2486
2556
 
2487
2557
 
2488
2558
  ## Containers
package/event.js CHANGED
@@ -343,14 +343,14 @@ module.EventDocMixin = object.Mixin('EventDocMixin', {
343
343
  return object.deepKeys(this)
344
344
  .filter(function(n){
345
345
  // avoid triggering props...
346
- return !object.values(this, n, function(){ return object.STOP }, true)[0].get
346
+ return !object.values(this, n, true).next().value.get
347
347
  // XXX this is too strict...
348
348
  && (this[n] || {}).constructor === Eventful}.bind(this)) },
349
349
  get events(){
350
350
  return object.deepKeys(this)
351
351
  .filter(function(n){
352
352
  // avoid triggering props...
353
- return !object.values(this, n, function(){ return object.STOP }, true)[0].get
353
+ return !object.values(this, n, true).next().value.get
354
354
  // XXX this is too strict...
355
355
  && (this[n] || {}).constructor === Event }.bind(this)) },
356
356
  })
package/generator.js CHANGED
@@ -8,6 +8,7 @@
8
8
  /*********************************************************************/
9
9
 
10
10
  var object = require('ig-object')
11
+ var stoppable = require('ig-stoppable')
11
12
 
12
13
 
13
14
 
@@ -16,7 +17,7 @@ var object = require('ig-object')
16
17
  // NOTE: this is used in a similar fashion to Python's StopIteration...
17
18
  var STOP =
18
19
  module.STOP =
19
- object.STOP
20
+ stoppable.STOP
20
21
 
21
22
 
22
23
  //---------------------------------------------------------------------
@@ -38,11 +39,11 @@ module.STOP =
38
39
  // of each of them.
39
40
  // So, below we will define:
40
41
  //
41
- // GeneratorPrototype
42
+ // Generator.prototype
42
43
  // prototype of the generator constructors (i.e. Iter(..) from the
43
44
  // above example)
44
45
  //
45
- // GeneratorPrototype.prototype
46
+ // Generator.prototype.prototype
46
47
  // generator instance prototype (i.e. iter for the above code)
47
48
  //
48
49
  //
@@ -58,13 +59,14 @@ module.STOP =
58
59
  //
59
60
  //---------------------------------------------------------------------
60
61
 
61
- var GeneratorPrototype =
62
- (function*(){}).constructor.prototype
63
-
64
62
  var Generator =
65
63
  module.Generator =
66
64
  (function*(){}).constructor
67
65
 
66
+ var AsyncGenerator =
67
+ module.AsyncGenerator =
68
+ (async function*(){}).constructor
69
+
68
70
 
69
71
  // base iterator prototypes...
70
72
  var ITERATOR_PROTOTYPES = [
@@ -77,19 +79,44 @@ var ITERATOR_PROTOTYPES = [
77
79
 
78
80
 
79
81
  //---------------------------------------------------------------------
80
-
81
82
  // generic generator wrapper...
83
+
84
+ // helper...
85
+ var __iter =
86
+ module.__iter =
87
+ function*(lst=[]){
88
+ if(typeof(lst) == 'object'
89
+ && Symbol.iterator in lst){
90
+ yield* lst
91
+ } else {
92
+ yield lst } }
93
+
94
+ // XXX updatae Array.js' version for compatibility...
95
+ // XXX DOCS!!!
82
96
  var iter =
83
97
  module.iter =
84
98
  Generator.iter =
85
- function*(lst=[]){
86
- for(var e of lst){
87
- yield e } }
99
+ stoppable(function(lst=[]){
100
+ // handler -> generator-constructor...
101
+ if(typeof(lst) == 'function'){
102
+ // we need to be callable...
103
+ var that = this instanceof Function ?
104
+ this
105
+ // generic root generator...
106
+ : module.__iter
107
+ return function*(){
108
+ yield* that(...arguments).iter(lst) } }
109
+ // no handler -> generator instance...
110
+ return module.__iter(lst) })
111
+
112
+ // NOTE: we need .iter(..) to both return generators if passed an iterable
113
+ // and genereator constructos if passed a function...
114
+ iter.__proto__ = Generator.prototype
88
115
 
89
116
 
90
117
 
91
118
  //---------------------------------------------------------------------
92
- // GeneratorPrototype "class" methods...
119
+ // Generator.prototype "class" methods...
93
120
  //
94
121
  // the following are effectively the same:
95
122
  // 1) Wrapper
@@ -113,9 +140,11 @@ Generator.iter =
113
140
 
114
141
  //
115
142
  // makeGenerator(<name>)
143
+ // makeGenerator(<name>, <handler>)
116
144
  // -> <func>
117
145
  //
118
- // makeGenerator(<name>, <handler>)
146
+ // makeGenerator('async', <name>)
147
+ // makeGenerator('async', <name>, <handler>)
119
148
  // -> <func>
120
149
  //
121
150
  //
@@ -132,14 +161,26 @@ Generator.iter =
132
161
  // XXX this needs to be of the correct type... (???)
133
162
  // XXX need to accept generators as handlers...
134
163
  var makeGenerator = function(name, pre){
164
+ var sync = true
165
+ if(name == 'async'){
166
+ sync = false
167
+ var [name, pre] = [...arguments].slice(1) }
135
168
  return function(...args){
136
169
  var that = this
137
170
  return Object.assign(
138
- function*(){
139
- var a = pre ?
140
- pre.call(this, args, ...arguments)
141
- : args
142
- yield* that(...arguments)[name](...a) },
171
+ // NOTE: the two branches here are identical, the only
172
+ // difference is the async keyword...
173
+ sync ?
174
+ function*(){
175
+ var a = pre ?
176
+ pre.call(this, args, ...arguments)
177
+ : args
178
+ yield* that(...arguments)[name](...a) }
179
+ : async function*(){
180
+ var a = pre ?
181
+ pre.call(this, args, ...arguments)
182
+ : args
183
+ yield* that(...arguments)[name](...a) },
143
184
  { toString: function(){
144
185
  return [
145
186
  that.toString(),
@@ -155,34 +196,6 @@ var makePromise = function(name){
155
196
  return that(...arguments)[name](func) } } }
156
197
 
157
198
 
158
- var stoppable =
159
- module.stoppable =
160
- function(func){
161
- return Object.assign(
162
- func instanceof Generator ?
163
- function*(){
164
- try{
165
- yield* func.call(this, ...arguments)
166
- } catch(err){
167
- if(err === STOP){
168
- return
169
- } else if(err instanceof STOP){
170
- yield err.value
171
- return }
172
- throw err } }
173
- : function(){
174
- try{
175
- return func.call(this, ...arguments)
176
- } catch(err){
177
- if(err === STOP){
178
- return
179
- } else if(err instanceof STOP){
180
- return err.value }
181
- throw err } },
182
- { toString: function(){
183
- return func.toString() }, }) }
184
-
185
-
186
199
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
187
200
 
188
201
  var GeneratorMixin =
@@ -190,9 +203,7 @@ module.GeneratorMixin =
190
203
  object.Mixin('GeneratorMixin', 'soft', {
191
204
  STOP: object.STOP,
192
205
 
193
- // NOTE: this is here for compatibility with Array.iter(..)
194
- iter: function*(lst=[]){
195
- yield* module.iter(lst) },
206
+ iter: module.iter,
196
207
 
197
208
  gat: makeGenerator('gat'),
198
209
  at: function(i){
@@ -221,7 +232,7 @@ object.Mixin('GeneratorMixin', 'soft', {
221
232
  return that(...arguments).toArray() },
222
233
  { toString: function(){
223
234
  return that.toString()
224
- + '\n .toString()'}, }) },
235
+ + '\n .toArray()'}, }) },
225
236
  gpop: makeGenerator('gpop'),
226
237
  pop: function(){
227
238
  var that = this
@@ -231,7 +242,7 @@ object.Mixin('GeneratorMixin', 'soft', {
231
242
  return that(...arguments).pop() },
232
243
  { toString: function(){
233
244
  return that.toString()
234
- + '\n .gpop()'}, }) },
245
+ + '\n .pop()'}, }) },
235
246
  push: makeGenerator('push'),
236
247
  gshift: makeGenerator('gshift'),
237
248
  shift: function(){
@@ -242,7 +253,7 @@ object.Mixin('GeneratorMixin', 'soft', {
242
253
  return that(...arguments).shift() },
243
254
  { toString: function(){
244
255
  return that.toString()
245
- + '\n .gshift()'}, }) },
256
+ + '\n .shift()'}, }) },
246
257
  unshift: makeGenerator('unshift'),
247
258
 
248
259
  // promises...
@@ -264,15 +275,43 @@ object.Mixin('GeneratorMixin', 'soft', {
264
275
  e(...args)
265
276
  : e }) }),
266
277
  //zip: makeGenerator('zip'),
278
+
279
+ enumerate: makeGenerator('enumerate'),
280
+
281
+ // XXX should this have a .gjoin(..) companion...
282
+ join: function(){
283
+ var args = [...arguments]
284
+ var that = this
285
+ return Object.assign(
286
+ function(){
287
+ //return that(...arguments).toArray().shift() },
288
+ return that(...arguments).join(...args) },
289
+ { toString: function(){
290
+ return that.toString()
291
+ + '\n .join()'}, }) },
267
292
  })
268
293
 
269
294
 
270
295
  var GeneratorProtoMixin =
271
296
  module.GeneratorProtoMixin =
272
297
  object.Mixin('GeneratorProtoMixin', 'soft', {
273
- // NOTE: this is here for compatibility with [..].iter()
274
- iter: function*(){
275
- yield* this },
298
+ // XXX use module.iter(..) ???
299
+ iter: stoppable(function*(handler){
300
+ if(handler){
301
+ var i = 0
302
+ for(var elem of this){
303
+ var res = handler.call(this, elem, i)
304
+ // expand iterables...
305
+ if(typeof(res) == 'object'
306
+ && Symbol.iterator in res){
307
+ yield* res
308
+ // as-is...
309
+ } else {
310
+ yield res }}
311
+ // no handler...
312
+ } else {
313
+ yield* this } }),
314
+ //*/
276
315
 
277
316
  at: function(i){
278
317
  return this.gat(i).next().value },
@@ -382,17 +421,19 @@ object.Mixin('GeneratorProtoMixin', 'soft', {
382
421
 
383
422
  // promises...
384
423
  //
385
- // XXX how do we handle reject(..) / .catch(..)???
386
- promise: function(){
424
+ then: function(onresolve, onreject){
387
425
  var that = this
388
- return new Promise(function(resolve){
389
- resolve([...that]) }) },
390
- then: function(func){
391
- return this.promise().then(func) },
426
+ var p = new Promise(
427
+ function(resolve){
428
+ resolve([...that]) })
429
+ p = (onresolve || onreject) ?
430
+ p.then(...arguments)
431
+ : p
432
+ return p },
392
433
  catch: function(func){
393
- return this.promise().catch(func) },
434
+ return this.then().catch(func) },
394
435
  finally: function(func){
395
- return this.promise().finally(func) },
436
+ return this.then().finally(func) },
396
437
 
397
438
  // combinators...
398
439
  //
@@ -415,11 +456,20 @@ object.Mixin('GeneratorProtoMixin', 'soft', {
415
456
  // XXX
416
457
  },
417
458
  //*/
459
+
460
+ enumerate: function*(){
461
+ var i = 0
462
+ for(var e of this){
463
+ yield [i++, e] } },
464
+
465
+ join: function(){
466
+ return [...this]
467
+ .join(...arguments) },
418
468
  })
419
469
 
420
470
 
421
- GeneratorMixin(GeneratorPrototype)
422
- GeneratorProtoMixin(GeneratorPrototype.prototype)
471
+ GeneratorMixin(Generator.prototype)
472
+ GeneratorProtoMixin(Generator.prototype.prototype)
423
473
 
424
474
 
425
475
  // Extend base iterators...
@@ -428,6 +478,111 @@ ITERATOR_PROTOTYPES
428
478
  GeneratorProtoMixin(proto) })
429
479
 
430
480
 
481
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
482
+ // XXX EXPERIMENTAL...
483
+
484
+ var AsyncGeneratorMixin =
485
+ module.AsyncGeneratorMixin =
486
+ object.Mixin('AsyncGeneratorMixin', 'soft', {
487
+ // XXX TEST...
488
+ iter: makeGenerator('async', 'iter'),
489
+
490
+ map: makeGenerator('async', 'map'),
491
+ filter: makeGenerator('async', 'filter'),
492
+ reduce: makeGenerator('async', 'reduce'),
493
+ })
494
+
495
+ var AsyncGeneratorProtoMixin =
496
+ module.AsyncGeneratorProtoMixin =
497
+ object.Mixin('AsyncGeneratorProtoMixin', 'soft', {
498
+ // promise...
499
+ //
500
+ // NOTE: this will unwind the generator...
501
+ // XXX create an iterator promise???
502
+ // XXX should we unwind???
503
+ then: function(resolve, reject){
504
+ var that = this
505
+ var p = new Promise(async function(_resolve, _reject){
506
+ var res = []
507
+ for await(var elem of that){
508
+ res.push(elem) }
509
+ _resolve(res) })
510
+ p = (resolve || reject) ?
511
+ p.then(...arguments)
512
+ : p
513
+ return p },
514
+ catch: function(func){
515
+ return this.then().catch(func) },
516
+ finally: function(){
517
+ return this.then().finally(func) },
518
+
519
+ // XXX might be a good idea to use this approach above...
520
+ iter: stoppable(async function*(handler=undefined){
521
+ var i = 0
522
+ if(handler){
523
+ for await(var e of this){
524
+ var res = handler.call(this, e, i++)
525
+ if(typeof(res) == 'object'
526
+ && Symbol.iterator in res){
527
+ yield* res
528
+ } else {
529
+ yield res } }
530
+ } else {
531
+ yield* this } }),
532
+
533
+ map: async function*(func){
534
+ yield* this.iter(function(elem, i){
535
+ return [func.call(this, elem, i)] }) },
536
+ filter: async function*(func){
537
+ yield* this.iter(function(elem, i){
538
+ return func.call(this, elem, i) ?
539
+ [elem]
540
+ : [] }) },
541
+ // NOTE: there is not much point in .reduceRight(..) in an async
542
+ // generator as we'll need to fully unwind it then go from the
543
+ // end...
544
+ reduce: async function(func, state){
545
+ this.iter(function(elem, i){
546
+ state = func.call(this, state, elem, i)
547
+ return [] })
548
+ return state },
549
+
550
+ // XXX TEST...
551
+ chain: async function*(...next){
552
+ yield* next
553
+ .reduce(function(cur, next){
554
+ return next(cur) }, this) },
555
+
556
+ flat: async function*(){
557
+ for await(var e of this){
558
+ if(e instanceof Array){
559
+ yield* e
560
+ } else {
561
+ yield e }}},
562
+
563
+ concat: async function*(other){
564
+ yield* this
565
+ yield* other },
566
+ push: async function*(elem){
567
+ yield* this
568
+ yield elem },
569
+ unsift: async function*(elem){
570
+ yield elem
571
+ yield* this },
572
+
573
+ join: async function(){
574
+ return [...(await this)]
575
+ .join(...arguments) },
576
+
577
+ // XXX
578
+ // slice -- not sure if we need this...
579
+ // ...
580
+ })
581
+
582
+ AsyncGeneratorMixin(AsyncGenerator.prototype)
583
+ AsyncGeneratorProtoMixin(AsyncGenerator.prototype.prototype)
584
+
585
+
431
586
 
432
587
  //---------------------------------------------------------------------
433
588
  // Generators...
package/main.js CHANGED
@@ -22,6 +22,7 @@ module.patchDate = require('./Date').patchDate
22
22
 
23
23
  // Additional types...
24
24
  module.containers = require('./containers')
25
+ module.func = require('./Function')
25
26
  module.generator = require('./generator')
26
27
  module.event = require('./event')
27
28
  module.runner = require('./runner')
@@ -31,7 +32,9 @@ module.runner = require('./runner')
31
32
  module.STOP = object.STOP
32
33
 
33
34
  // frequently used stuff...
35
+ module.AsyncFunction = module.func.AsyncFunction
34
36
  module.Generator = module.generator.Generator
37
+ module.AsyncGenerator = module.generator.AsyncGenerator
35
38
  // XXX doc...
36
39
  module.iter = module.generator.iter
37
40
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ig-types",
3
- "version": "6.15.0",
3
+ "version": "6.16.0",
4
4
  "description": "Generic JavaScript types and type extensions...",
5
5
  "main": "main.js",
6
6
  "scripts": {
@@ -23,7 +23,8 @@
23
23
  },
24
24
  "homepage": "https://github.com/flynx/types.js#readme",
25
25
  "dependencies": {
26
- "ig-object": "^5.4.16",
26
+ "ig-object": "^6.0.0",
27
+ "ig-stoppable": "^2.0.0",
27
28
  "object-run": "^1.0.1"
28
29
  },
29
30
  "devDependencies": {