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 +24 -6
- package/Function.js +18 -0
- package/Promise.js +31 -25
- package/README.md +83 -13
- package/event.js +2 -2
- package/generator.js +219 -64
- package/main.js +3 -0
- package/package.json +3 -2
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
|
-
|
|
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
|
-
|
|
216
|
-
|
|
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
|
-
|
|
492
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
241
|
-
|
|
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
|
-
|
|
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>.
|
|
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>.
|
|
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(<
|
|
2225
|
+
<generator>.then(<resolve>)
|
|
2177
2226
|
-> <promise>
|
|
2178
2227
|
|
|
2179
2228
|
<generator>.finally(<handler>)
|
|
2180
2229
|
-> <promise>
|
|
2181
2230
|
```
|
|
2182
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
//
|
|
42
|
+
// Generator.prototype
|
|
42
43
|
// prototype of the generator constructors (i.e. Iter(..) from the
|
|
43
44
|
// above example)
|
|
44
45
|
//
|
|
45
|
-
//
|
|
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
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
//
|
|
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
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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 .
|
|
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 .
|
|
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 .
|
|
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
|
-
//
|
|
274
|
-
iter: function*(){
|
|
275
|
-
|
|
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
|
-
|
|
386
|
-
promise: function(){
|
|
424
|
+
then: function(onresolve, onreject){
|
|
387
425
|
var that = this
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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.
|
|
434
|
+
return this.then().catch(func) },
|
|
394
435
|
finally: function(func){
|
|
395
|
-
return this.
|
|
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(
|
|
422
|
-
GeneratorProtoMixin(
|
|
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.
|
|
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": "^
|
|
26
|
+
"ig-object": "^6.0.0",
|
|
27
|
+
"ig-stoppable": "^2.0.0",
|
|
27
28
|
"object-run": "^1.0.1"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|