ig-types 6.10.1 → 6.11.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.
- package/Array.js +1 -0
- package/Promise.js +154 -64
- package/Promise.js.bak +548 -0
- package/README.md +102 -3
- package/RegExp.js +2 -1
- package/generator.js +1 -0
- package/package.json +1 -1
package/Array.js
CHANGED
|
@@ -492,6 +492,7 @@ object.Mixin('ArrayProtoMixin', 'soft', {
|
|
|
492
492
|
smap: stoppableList('map'),
|
|
493
493
|
sfilter: stoppableList('filter'),
|
|
494
494
|
sreduce: stoppableValue('reduce'),
|
|
495
|
+
sreduceRight: stoppableValue('reduceRight'),
|
|
495
496
|
sforEach: stoppableValue('map', true),
|
|
496
497
|
|
|
497
498
|
// Chunk iteration...
|
package/Promise.js
CHANGED
|
@@ -80,12 +80,13 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
80
80
|
// NOTE: these are different to Array's equivalents in that the handler
|
|
81
81
|
// is called not in the order of the elements but rather in order
|
|
82
82
|
// of promise resolution...
|
|
83
|
-
// NOTE: index of items is unknowable because items can expand
|
|
83
|
+
// NOTE: index of items is unknowable because items can expand and
|
|
84
84
|
// contract depending on handlrs (e.g. .filter(..) can remove
|
|
85
85
|
// items)...
|
|
86
86
|
// This the following can not be implemented here:
|
|
87
87
|
// .slice(..)
|
|
88
88
|
// .splice(..)
|
|
89
|
+
// .values() / .keys()
|
|
89
90
|
// .at(..)
|
|
90
91
|
// [Symbol.iterator]() - needs to be sync...
|
|
91
92
|
// The followng methods are questionable:
|
|
@@ -93,36 +94,65 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
93
94
|
// .includes(..)
|
|
94
95
|
// .some(..) / .every(..)
|
|
95
96
|
// .sort(..)
|
|
97
|
+
//
|
|
96
98
|
// XXX should these support STOP???
|
|
97
99
|
map: function(func){
|
|
98
|
-
return this.constructor(this
|
|
100
|
+
return this.constructor(this,
|
|
99
101
|
function(e){
|
|
100
102
|
return [func(e)] }) },
|
|
101
103
|
filter: function(func){
|
|
102
|
-
return this.constructor(this
|
|
104
|
+
return this.constructor(this,
|
|
103
105
|
function(e){
|
|
104
106
|
return func(e) ?
|
|
105
107
|
[e]
|
|
106
108
|
: [] }) },
|
|
109
|
+
// NOTE: this does not return an iterable promise as we can't know
|
|
110
|
+
// what the user reduces to...
|
|
111
|
+
// XXX we could look at the initial state though...
|
|
112
|
+
// NOTE: the items can be handled out of order because the nested
|
|
113
|
+
// promises can resolve in any order.
|
|
114
|
+
// XXX write how to go around this...
|
|
115
|
+
// NOTE: since order of execution can not be guaranteed there is no
|
|
116
|
+
// point in implementing .reduceRight(..)
|
|
107
117
|
reduce: function(func, res){
|
|
108
|
-
return this.constructor(this
|
|
118
|
+
return this.constructor(this,
|
|
109
119
|
function(e){
|
|
110
120
|
res = func(res, e)
|
|
111
121
|
return [] })
|
|
112
122
|
.then(function(){
|
|
113
123
|
return res }) },
|
|
114
124
|
flat: function(depth=1){
|
|
115
|
-
return this.constructor(this
|
|
125
|
+
return this.constructor(this,
|
|
116
126
|
function(e){
|
|
117
|
-
return (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
return (depth > 1
|
|
128
|
+
&& e != null
|
|
129
|
+
&& e.flat) ?
|
|
130
|
+
e.flat(depth-1)
|
|
131
|
+
: depth != 0 ?
|
|
132
|
+
e
|
|
133
|
+
: [e] }) },
|
|
134
|
+
reverse: function(){
|
|
135
|
+
var lst = this.__list
|
|
136
|
+
return this.constructor(
|
|
137
|
+
lst instanceof Promise ?
|
|
138
|
+
lst.then(function(elems){
|
|
139
|
+
return elems instanceof Array ?
|
|
140
|
+
elems.slice()
|
|
141
|
+
.reverse()
|
|
142
|
+
: elems })
|
|
143
|
+
: lst
|
|
144
|
+
.map(function(elems){
|
|
145
|
+
return elems instanceof Array ?
|
|
146
|
+
elems.slice()
|
|
147
|
+
.reverse()
|
|
148
|
+
: elems instanceof Promise ?
|
|
149
|
+
elems.then(function(elems){
|
|
150
|
+
return elems.reverse() })
|
|
151
|
+
: elems })
|
|
152
|
+
.reverse(),
|
|
153
|
+
'raw') },
|
|
154
|
+
|
|
155
|
+
// XXX do we need these?
|
|
126
156
|
// .pop()
|
|
127
157
|
// .shift()
|
|
128
158
|
// .first() / .last()
|
|
@@ -182,8 +212,8 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
182
212
|
//
|
|
183
213
|
// Spectial cases usefull for extending this constructor...
|
|
184
214
|
//
|
|
185
|
-
//
|
|
186
|
-
// Promise.iter([ .. ],
|
|
215
|
+
// Set raw .__list without any pre-processing...
|
|
216
|
+
// Promise.iter([ .. ], 'raw')
|
|
187
217
|
// -> iterable-promise
|
|
188
218
|
//
|
|
189
219
|
// Create a rejected iterator...
|
|
@@ -204,9 +234,8 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
204
234
|
// - another issue here is that the stop would happen in order of
|
|
205
235
|
// execution and not order of elements...
|
|
206
236
|
__new__: function(_, list, handler){
|
|
207
|
-
var promise
|
|
208
|
-
|
|
209
237
|
// instance...
|
|
238
|
+
var promise
|
|
210
239
|
var obj = Reflect.construct(
|
|
211
240
|
IterablePromise.__proto__,
|
|
212
241
|
[function(resolve, reject){
|
|
@@ -220,49 +249,47 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
220
249
|
IterablePromise)
|
|
221
250
|
|
|
222
251
|
if(promise){
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
return
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
// clone...
|
|
265
|
-
: list.slice()
|
|
252
|
+
|
|
253
|
+
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) }
|
|
266
293
|
|
|
267
294
|
Object.defineProperty(obj, '__list', {
|
|
268
295
|
value: list,
|
|
@@ -270,9 +297,14 @@ object.Constructor('IterablePromise', Promise, {
|
|
|
270
297
|
})
|
|
271
298
|
|
|
272
299
|
// handle promise state...
|
|
273
|
-
|
|
300
|
+
;(list instanceof Promise ?
|
|
301
|
+
// special case: promised list...
|
|
302
|
+
list
|
|
303
|
+
: Promise.all([list].flat()))
|
|
274
304
|
.then(function(res){
|
|
275
|
-
promise.resolve(
|
|
305
|
+
promise.resolve(handler ?
|
|
306
|
+
res.flat()
|
|
307
|
+
: res) })
|
|
276
308
|
.catch(promise.reject) }
|
|
277
309
|
|
|
278
310
|
return obj },
|
|
@@ -415,6 +447,51 @@ object.Constructor('CooperativePromise', Promise, {
|
|
|
415
447
|
|
|
416
448
|
|
|
417
449
|
|
|
450
|
+
//---------------------------------------------------------------------
|
|
451
|
+
|
|
452
|
+
// XXX EXPEREMENTAL...
|
|
453
|
+
var ProxyPromise =
|
|
454
|
+
module.ProxyPromise =
|
|
455
|
+
object.Constructor('ProxyPromise', Promise, {
|
|
456
|
+
__new__: function(context, constructor){
|
|
457
|
+
var proto = 'prototype' in constructor ?
|
|
458
|
+
constructor.prototype
|
|
459
|
+
: constructor
|
|
460
|
+
var obj = Reflect.construct(
|
|
461
|
+
ProxyPromise.__proto__,
|
|
462
|
+
[function(resolve, reject){
|
|
463
|
+
context.then(resolve)
|
|
464
|
+
context.catch(reject) }],
|
|
465
|
+
ProxyPromise)
|
|
466
|
+
// populate...
|
|
467
|
+
// NOTE: we are not using object.deepKeys(..) here as we need
|
|
468
|
+
// the key origin not to trigger property getters...
|
|
469
|
+
var seen = new Set()
|
|
470
|
+
while(proto != null){
|
|
471
|
+
Object.entries(Object.getOwnPropertyDescriptors(proto))
|
|
472
|
+
.forEach(function([key, value]){
|
|
473
|
+
// skip overloaded keys...
|
|
474
|
+
if(seen.has(key)){
|
|
475
|
+
return }
|
|
476
|
+
// skip non-functions...
|
|
477
|
+
if(typeof(value.value) != 'function'){
|
|
478
|
+
return }
|
|
479
|
+
// skip non-enumerable except for Object.prototype.run(..)...
|
|
480
|
+
if(!(key == 'run'
|
|
481
|
+
&& Object.prototype.run === value.value)
|
|
482
|
+
&& !value.enumerable){
|
|
483
|
+
return }
|
|
484
|
+
// proxy...
|
|
485
|
+
obj[key] = function(...args){
|
|
486
|
+
// XXX should we also .catch(..) here???
|
|
487
|
+
return context.then(function(res){
|
|
488
|
+
return res[key](...args) }) } })
|
|
489
|
+
proto = proto.__proto__ }
|
|
490
|
+
return obj },
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
|
|
418
495
|
//---------------------------------------------------------------------
|
|
419
496
|
|
|
420
497
|
var PromiseMixin =
|
|
@@ -425,10 +502,23 @@ object.Mixin('PromiseMixin', 'soft', {
|
|
|
425
502
|
cooperative: CooperativePromise,
|
|
426
503
|
})
|
|
427
504
|
|
|
428
|
-
|
|
429
505
|
PromiseMixin(Promise)
|
|
430
506
|
|
|
431
507
|
|
|
508
|
+
// XXX EXPEREMENTAL...
|
|
509
|
+
var PromiseProtoMixin =
|
|
510
|
+
module.PromiseProtoMixin =
|
|
511
|
+
object.Mixin('PromiseProtoMixin', 'soft', {
|
|
512
|
+
as: ProxyPromise,
|
|
513
|
+
|
|
514
|
+
// XXX
|
|
515
|
+
iter: function(){
|
|
516
|
+
return IterablePromise(this) },
|
|
517
|
+
})
|
|
518
|
+
|
|
519
|
+
PromiseProtoMixin(Promise.prototype)
|
|
520
|
+
|
|
521
|
+
|
|
432
522
|
|
|
433
523
|
|
|
434
524
|
/**********************************************************************
|
package/Promise.js.bak
ADDED
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
/**********************************************************************
|
|
2
|
+
*
|
|
3
|
+
*
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* This defines the following extensions to Promise:
|
|
7
|
+
*
|
|
8
|
+
* Promise.iter(seq)
|
|
9
|
+
* Iterable promise object.
|
|
10
|
+
* Similar to Promise.all(..) but adds basic iterator/generator
|
|
11
|
+
* API and will resolve the items as they are ready (resolved).
|
|
12
|
+
*
|
|
13
|
+
* Promise.interactive(handler)
|
|
14
|
+
* Interactive promise object.
|
|
15
|
+
* This adds a basic message passing API to the promise.
|
|
16
|
+
*
|
|
17
|
+
* Promise.cooperative()
|
|
18
|
+
* Cooperative promise object.
|
|
19
|
+
* Exposes the API to resolve/reject the promise object
|
|
20
|
+
* externally.
|
|
21
|
+
*
|
|
22
|
+
*
|
|
23
|
+
*
|
|
24
|
+
**********************************************/ /* c8 ignore next 2 */
|
|
25
|
+
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
26
|
+
(function(require){ var module={} // make module AMD/node compatible...
|
|
27
|
+
/*********************************************************************/
|
|
28
|
+
|
|
29
|
+
var object = require('ig-object')
|
|
30
|
+
|
|
31
|
+
// XXX required for STOP...
|
|
32
|
+
//var generator = require('./generator')
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
/*********************************************************************/
|
|
36
|
+
|
|
37
|
+
/* XXX not used yet...
|
|
38
|
+
// NOTE: this is used in a similar fashion to Python's StopIteration...
|
|
39
|
+
var STOP =
|
|
40
|
+
module.STOP =
|
|
41
|
+
object.STOP
|
|
42
|
+
//*/
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
//---------------------------------------------------------------------
|
|
46
|
+
// Iterable promise...
|
|
47
|
+
//
|
|
48
|
+
// Like Promise.all(..) but adds ability to iterate through results
|
|
49
|
+
// via generators .map(..)/.reduce(..) and friends...
|
|
50
|
+
//
|
|
51
|
+
|
|
52
|
+
var IterablePromise =
|
|
53
|
+
module.IterablePromise =
|
|
54
|
+
object.Constructor('IterablePromise', Promise, {
|
|
55
|
+
// XXX
|
|
56
|
+
//STOP: object.STOP,
|
|
57
|
+
|
|
58
|
+
//
|
|
59
|
+
// Format:
|
|
60
|
+
// [
|
|
61
|
+
// [ <value> ],
|
|
62
|
+
// <promise>,
|
|
63
|
+
// ...
|
|
64
|
+
// ]
|
|
65
|
+
//
|
|
66
|
+
__list: null,
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
// iterator methods...
|
|
70
|
+
//
|
|
71
|
+
// These will return a new IterablePromise instance...
|
|
72
|
+
//
|
|
73
|
+
// When called from a resolved promise these will return a new
|
|
74
|
+
// resolved promise with updated values...
|
|
75
|
+
//
|
|
76
|
+
// When called from a rejected promise these will return a rejected
|
|
77
|
+
// with the same reason promise...
|
|
78
|
+
//
|
|
79
|
+
//
|
|
80
|
+
// NOTE: these are different to Array's equivalents in that the handler
|
|
81
|
+
// is called not in the order of the elements but rather in order
|
|
82
|
+
// of promise resolution...
|
|
83
|
+
// NOTE: index of items is unknowable because items can expand and
|
|
84
|
+
// contract depending on handlrs (e.g. .filter(..) can remove
|
|
85
|
+
// items)...
|
|
86
|
+
// This the following can not be implemented here:
|
|
87
|
+
// .slice(..)
|
|
88
|
+
// .splice(..)
|
|
89
|
+
// .values() / .keys()
|
|
90
|
+
// .at(..)
|
|
91
|
+
// [Symbol.iterator]() - needs to be sync...
|
|
92
|
+
// The followng methods are questionable:
|
|
93
|
+
// .indexOf(..)
|
|
94
|
+
// .includes(..)
|
|
95
|
+
// .some(..) / .every(..)
|
|
96
|
+
// .sort(..)
|
|
97
|
+
// XXX BUG:
|
|
98
|
+
// Promise.iter([1,2,3])
|
|
99
|
+
// .map(e => e)
|
|
100
|
+
// is not the same as:
|
|
101
|
+
// Promise.iter([1,2,3])
|
|
102
|
+
// .map(e => e)
|
|
103
|
+
// .map(e => e)
|
|
104
|
+
// XXX should these support STOP???
|
|
105
|
+
map: function(func){
|
|
106
|
+
return this.constructor(this.__list.flat(),
|
|
107
|
+
function(e){
|
|
108
|
+
return [func(e)] }) },
|
|
109
|
+
filter: function(func){
|
|
110
|
+
return this.constructor(this.__list.flat(),
|
|
111
|
+
function(e){
|
|
112
|
+
return func(e) ?
|
|
113
|
+
[e]
|
|
114
|
+
: [] }) },
|
|
115
|
+
// NOTE: this does not return an iterable promise as we can't know
|
|
116
|
+
// what the user reduces to...
|
|
117
|
+
// NOTE: the items can be handled out of order because the nested
|
|
118
|
+
// promises can resolve in any order.
|
|
119
|
+
// XXX write how to go around this...
|
|
120
|
+
// NOTE: since order of execution can not be guaranteed there is no
|
|
121
|
+
// point in implementing .reduceRight(..)
|
|
122
|
+
reduce: function(func, res){
|
|
123
|
+
return this.constructor(this.__list.flat(),
|
|
124
|
+
function(e){
|
|
125
|
+
res = func(res, e)
|
|
126
|
+
return [] })
|
|
127
|
+
.then(function(){
|
|
128
|
+
return res }) },
|
|
129
|
+
flat: function(depth=1){
|
|
130
|
+
return this.constructor(this.__list.flat(),
|
|
131
|
+
function(e){
|
|
132
|
+
return (depth > 1
|
|
133
|
+
&& e != null
|
|
134
|
+
&& e.flat) ?
|
|
135
|
+
e.flat(depth-1)
|
|
136
|
+
: depth != 0 ?
|
|
137
|
+
e
|
|
138
|
+
: [e] }) },
|
|
139
|
+
// XXX REVERSE...
|
|
140
|
+
// XXX BUG:
|
|
141
|
+
// await Promise.iter([1, Promise.iter(['a', ['b', 'c']]), [2, 3], 4])
|
|
142
|
+
// .flat()
|
|
143
|
+
// -> [ 1, 'a', [ 'b', 'c' ], 2, 3, 4 ]
|
|
144
|
+
// await Promise.iter([1, Promise.iter(['a', ['b', 'c']]), [2, 3], 4])
|
|
145
|
+
// .flat()
|
|
146
|
+
// .reverse()
|
|
147
|
+
// -> [ 4, 2, 3, [ 'b', 'c', 'a' ], 1 ]
|
|
148
|
+
// ...should be:
|
|
149
|
+
// -> [ 4, 2, 3, [ 'b', 'c' ], 'a', 1 ]
|
|
150
|
+
// it's odd we are not seeing this in other places...
|
|
151
|
+
reverse: function(){
|
|
152
|
+
return this.constructor(this.__list
|
|
153
|
+
.map(function(elems){
|
|
154
|
+
return elems && elems.then ?
|
|
155
|
+
elems.then(function(res){
|
|
156
|
+
return res
|
|
157
|
+
.reverse()
|
|
158
|
+
.flat() })
|
|
159
|
+
: elems })
|
|
160
|
+
.reverse()
|
|
161
|
+
.flat()) },
|
|
162
|
+
|
|
163
|
+
// compatibility with root promise...
|
|
164
|
+
// XXX BUG:
|
|
165
|
+
// await Promise.iter(Promise.resolve([1,2,[3, 4]])).iter()
|
|
166
|
+
// -> [ [ 1, 2, 3, 4 ] ]
|
|
167
|
+
iter: function(){
|
|
168
|
+
return this.constructor(
|
|
169
|
+
// clone and unwrap the .__list
|
|
170
|
+
this.__list
|
|
171
|
+
.map(function(elems){
|
|
172
|
+
return elems && elems.then ?
|
|
173
|
+
elems.then(function(res){
|
|
174
|
+
return res instanceof Array ?
|
|
175
|
+
res.flat()
|
|
176
|
+
: res })
|
|
177
|
+
: elems })
|
|
178
|
+
.flat()) },
|
|
179
|
+
|
|
180
|
+
// XXX do we need these?
|
|
181
|
+
// .pop()
|
|
182
|
+
// .shift()
|
|
183
|
+
// .first() / .last()
|
|
184
|
+
// XXX these can change the "resolved" state...
|
|
185
|
+
// ...i.e. return a pending promise when called from a fulfilled
|
|
186
|
+
// promise....
|
|
187
|
+
// .concat(..)
|
|
188
|
+
// .push(..)
|
|
189
|
+
// .unshift(..)
|
|
190
|
+
// .first(..) / .last(..)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
// Overload .then(..), .catch(..) and .finally(..) to return a plain
|
|
194
|
+
// Promise instnace...
|
|
195
|
+
//
|
|
196
|
+
// NOTE: .catch(..) and .finally(..) are implemented through .then(..)
|
|
197
|
+
// so we do not need to overload those...
|
|
198
|
+
// NOTE: this is slightly different from .then(..) in that it can be
|
|
199
|
+
// called without arguments and return a promise wrapper. This can
|
|
200
|
+
// be useful to hide special promise functionality...
|
|
201
|
+
then: function (onfulfilled, onrejected){
|
|
202
|
+
var p = new Promise(
|
|
203
|
+
function(resolve, reject){
|
|
204
|
+
Promise.prototype.then.call(this,
|
|
205
|
+
// NOTE: resolve(..) / reject(..) return undefined so
|
|
206
|
+
// we can't pass them directly here...
|
|
207
|
+
function(res){
|
|
208
|
+
resolve(res)
|
|
209
|
+
return res },
|
|
210
|
+
function(res){
|
|
211
|
+
reject(res)
|
|
212
|
+
return res }) }.bind(this))
|
|
213
|
+
return arguments.length > 0 ?
|
|
214
|
+
p.then(...arguments)
|
|
215
|
+
: p },
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
//
|
|
219
|
+
// Promise.iter([ .. ])
|
|
220
|
+
// -> iterable-promise
|
|
221
|
+
//
|
|
222
|
+
// Promise.iter([ .. ], handler)
|
|
223
|
+
// -> iterable-promise
|
|
224
|
+
//
|
|
225
|
+
//
|
|
226
|
+
// handler(e)
|
|
227
|
+
// -> [value]
|
|
228
|
+
// -> []
|
|
229
|
+
//
|
|
230
|
+
//
|
|
231
|
+
// NOTE: element index is unknowable untill the full list is expanded
|
|
232
|
+
// as handler(..)'s return value can expand to any number of
|
|
233
|
+
// items...
|
|
234
|
+
// XXX we can make the index a promise, then if the client needs
|
|
235
|
+
// the value they can wait for it...
|
|
236
|
+
//
|
|
237
|
+
//
|
|
238
|
+
// Spectial cases usefull for extending this constructor...
|
|
239
|
+
//
|
|
240
|
+
// Clone the iterator...
|
|
241
|
+
// Promise.iter([ .. ], false)
|
|
242
|
+
// -> iterable-promise
|
|
243
|
+
//
|
|
244
|
+
// Create a rejected iterator...
|
|
245
|
+
// Promise.iter(false)
|
|
246
|
+
// -> iterable-promise
|
|
247
|
+
//
|
|
248
|
+
//
|
|
249
|
+
// XXX if list is an iterator, can we fill this async???
|
|
250
|
+
// XXX iterator/generator as input:
|
|
251
|
+
// - do we unwind here or externally?
|
|
252
|
+
// ...feels like with the generator external unwinding is
|
|
253
|
+
// needed...
|
|
254
|
+
// XXX would be nice to support trowing STOP...
|
|
255
|
+
// - this is more complicated than simply suing .smap(..) instead
|
|
256
|
+
// of .map(..) because the list can contain async promises...
|
|
257
|
+
// ...would need to wrap each .then(..) call in try-catch and
|
|
258
|
+
// manually handle the stop...
|
|
259
|
+
// - another issue here is that the stop would happen in order of
|
|
260
|
+
// execution and not order of elements...
|
|
261
|
+
// XXX add support for list as a promise....
|
|
262
|
+
__new__: function(_, list, handler){
|
|
263
|
+
// handle: IterablePromise(<list>, <mode>)
|
|
264
|
+
if(typeof(handler) == 'string'){
|
|
265
|
+
mode = handler
|
|
266
|
+
handler = undefined }
|
|
267
|
+
|
|
268
|
+
// instance...
|
|
269
|
+
var promise
|
|
270
|
+
var obj = Reflect.construct(
|
|
271
|
+
IterablePromise.__proto__,
|
|
272
|
+
[function(resolve, reject){
|
|
273
|
+
// NOTE: this is here for Promise compatibilty...
|
|
274
|
+
if(typeof(list) == 'function'){
|
|
275
|
+
return list.call(this, ...arguments) }
|
|
276
|
+
// initial reject...
|
|
277
|
+
if(list === false){
|
|
278
|
+
return reject() }
|
|
279
|
+
promise = {resolve, reject} }],
|
|
280
|
+
IterablePromise)
|
|
281
|
+
|
|
282
|
+
if(promise){
|
|
283
|
+
// clone/normalize...
|
|
284
|
+
list =
|
|
285
|
+
// special case: promised list...
|
|
286
|
+
list instanceof Promise ?
|
|
287
|
+
list.then(function(res){
|
|
288
|
+
return [res] })
|
|
289
|
+
: [list].flat()
|
|
290
|
+
.map(function(e){
|
|
291
|
+
return (e && e.then) ?
|
|
292
|
+
e.then(function(e){
|
|
293
|
+
return [e] })
|
|
294
|
+
: [e] })
|
|
295
|
+
|
|
296
|
+
if(handler){
|
|
297
|
+
// NOTE: this is recursive to handle expanding nested promises...
|
|
298
|
+
var handle = function(elem){
|
|
299
|
+
// call the handler...
|
|
300
|
+
return (elem && elem.then) ?
|
|
301
|
+
elem.then(function(elems){
|
|
302
|
+
return elems
|
|
303
|
+
.map(handle)
|
|
304
|
+
.flat() })
|
|
305
|
+
: elem
|
|
306
|
+
.map(handler)
|
|
307
|
+
.flat() }
|
|
308
|
+
|
|
309
|
+
// handle the list...
|
|
310
|
+
//list = list.map(handle) }
|
|
311
|
+
list =
|
|
312
|
+
list instanceof Promise ?
|
|
313
|
+
// special case: promised list...
|
|
314
|
+
list.then(function(list){
|
|
315
|
+
return list.map(handle) })
|
|
316
|
+
: list.map(handle) }
|
|
317
|
+
|
|
318
|
+
Object.defineProperty(obj, '__list', {
|
|
319
|
+
value: list,
|
|
320
|
+
enumerable: false,
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
// handle promise state...
|
|
324
|
+
//Promise.all(list)
|
|
325
|
+
;(list instanceof Promise ?
|
|
326
|
+
// special case: promised list...
|
|
327
|
+
list
|
|
328
|
+
: Promise.all(list))
|
|
329
|
+
.then(function(res){
|
|
330
|
+
promise.resolve(res.flat()) })
|
|
331
|
+
.catch(promise.reject) }
|
|
332
|
+
|
|
333
|
+
return obj },
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
//---------------------------------------------------------------------
|
|
339
|
+
// Interactive promise...
|
|
340
|
+
//
|
|
341
|
+
// Adds ability to send messages to the running promise.
|
|
342
|
+
//
|
|
343
|
+
|
|
344
|
+
var InteractivePromise =
|
|
345
|
+
module.InteractivePromise =
|
|
346
|
+
object.Constructor('InteractivePromise', Promise, {
|
|
347
|
+
// XXX do we need a way to remove handlers???
|
|
348
|
+
__message_handlers: null,
|
|
349
|
+
|
|
350
|
+
send: function(...args){
|
|
351
|
+
var that = this
|
|
352
|
+
;(this.__message_handlers || [])
|
|
353
|
+
.forEach(function(h){ h.call(that, ...args) })
|
|
354
|
+
return this },
|
|
355
|
+
|
|
356
|
+
then: IterablePromise.prototype.then,
|
|
357
|
+
|
|
358
|
+
//
|
|
359
|
+
// Promise.interactive(handler)
|
|
360
|
+
// -> interacive-promise
|
|
361
|
+
//
|
|
362
|
+
// handler(resolve, reject, onmessage)
|
|
363
|
+
//
|
|
364
|
+
// onmessage(func)
|
|
365
|
+
//
|
|
366
|
+
//
|
|
367
|
+
__new__: function(_, handler){
|
|
368
|
+
var handlers = []
|
|
369
|
+
|
|
370
|
+
var onmessage = function(func){
|
|
371
|
+
// remove all handlers...
|
|
372
|
+
if(func === false){
|
|
373
|
+
var h = (obj == null ?
|
|
374
|
+
handlers
|
|
375
|
+
: (obj.__message_handlers || []))
|
|
376
|
+
h.splice(0, handlers.length)
|
|
377
|
+
// remove a specific handler...
|
|
378
|
+
} else if(arguments[1] === false){
|
|
379
|
+
var h = (obj == null ?
|
|
380
|
+
handlers
|
|
381
|
+
: (obj.__message_handlers || []))
|
|
382
|
+
h.splice(h.indexOf(func), 1)
|
|
383
|
+
// register a handler...
|
|
384
|
+
} else {
|
|
385
|
+
var h = obj == null ?
|
|
386
|
+
// NOTE: we need to get the handlers from .__message_handlers
|
|
387
|
+
// unless we are not fully defined yet, then use the
|
|
388
|
+
// bootstrap container (handlers)...
|
|
389
|
+
// ...since we can call onmessage(..) while the promise
|
|
390
|
+
// is still defined there is no way to .send(..) until it
|
|
391
|
+
// returns a promise object, this races here are highly
|
|
392
|
+
// unlikely...
|
|
393
|
+
handlers
|
|
394
|
+
: (obj.__message_handlers =
|
|
395
|
+
obj.__message_handlers ?? [])
|
|
396
|
+
handlers.push(func) } }
|
|
397
|
+
|
|
398
|
+
var obj = Reflect.construct(
|
|
399
|
+
InteractivePromise.__proto__,
|
|
400
|
+
!handler ?
|
|
401
|
+
[]
|
|
402
|
+
: [function(resolve, reject){
|
|
403
|
+
return handler(resolve, reject, onmessage) }],
|
|
404
|
+
InteractivePromise)
|
|
405
|
+
Object.defineProperty(obj, '__message_handlers', {
|
|
406
|
+
value: handlers,
|
|
407
|
+
enumerable: false,
|
|
408
|
+
// XXX should this be .configurable???
|
|
409
|
+
configurable: true,
|
|
410
|
+
})
|
|
411
|
+
return obj },
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
//---------------------------------------------------------------------
|
|
417
|
+
// Cooperative promise...
|
|
418
|
+
//
|
|
419
|
+
// A promise that can be resolved/rejected externally.
|
|
420
|
+
// NOTE: normally this has no internal resolver logic...
|
|
421
|
+
//
|
|
422
|
+
|
|
423
|
+
var CooperativePromise =
|
|
424
|
+
module.CooperativePromise =
|
|
425
|
+
object.Constructor('CooperativePromise', Promise, {
|
|
426
|
+
__handlers: null,
|
|
427
|
+
|
|
428
|
+
get isSet(){
|
|
429
|
+
return this.__handlers === false },
|
|
430
|
+
|
|
431
|
+
set: function(value, resolve=true){
|
|
432
|
+
// can't set twice...
|
|
433
|
+
if(this.isSet){
|
|
434
|
+
throw new Error('.set(..): can not set twice') }
|
|
435
|
+
// bind to promise...
|
|
436
|
+
if(value && value.then && value.catch){
|
|
437
|
+
value.then(handlers.resolve)
|
|
438
|
+
value.catch(handlers.reject)
|
|
439
|
+
// resolve with value...
|
|
440
|
+
} else {
|
|
441
|
+
resolve ?
|
|
442
|
+
this.__handlers.resolve(value)
|
|
443
|
+
: this.__handlers.reject(value) }
|
|
444
|
+
// cleanup and prevent setting twice...
|
|
445
|
+
this.__handlers = false
|
|
446
|
+
return this },
|
|
447
|
+
|
|
448
|
+
then: IterablePromise.prototype.then,
|
|
449
|
+
|
|
450
|
+
__new__: function(){
|
|
451
|
+
var handlers
|
|
452
|
+
var resolver = arguments[1]
|
|
453
|
+
|
|
454
|
+
var obj = Reflect.construct(
|
|
455
|
+
CooperativePromise.__proto__,
|
|
456
|
+
[function(resolve, reject){
|
|
457
|
+
handlers = {resolve, reject}
|
|
458
|
+
// NOTE: this is here to support builtin .then(..)
|
|
459
|
+
resolver
|
|
460
|
+
&& resolver(resolve, reject) }],
|
|
461
|
+
CooperativePromise)
|
|
462
|
+
|
|
463
|
+
Object.defineProperty(obj, '__handlers', {
|
|
464
|
+
value: handlers,
|
|
465
|
+
enumerable: false,
|
|
466
|
+
writable: true,
|
|
467
|
+
})
|
|
468
|
+
return obj },
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
//---------------------------------------------------------------------
|
|
474
|
+
|
|
475
|
+
// XXX EXPEREMENTAL...
|
|
476
|
+
var ProxyPromise =
|
|
477
|
+
module.ProxyPromise =
|
|
478
|
+
object.Constructor('ProxyPromise', Promise, {
|
|
479
|
+
__new__: function(context, constructor){
|
|
480
|
+
var proto = 'prototype' in constructor ?
|
|
481
|
+
constructor.prototype
|
|
482
|
+
: constructor
|
|
483
|
+
var obj = Reflect.construct(
|
|
484
|
+
ProxyPromise.__proto__,
|
|
485
|
+
[function(resolve, reject){
|
|
486
|
+
context.then(resolve)
|
|
487
|
+
context.catch(reject) }],
|
|
488
|
+
ProxyPromise)
|
|
489
|
+
// populate...
|
|
490
|
+
// NOTE: we are not using object.deepKeys(..) here as we need
|
|
491
|
+
// the key origin not to trigger property getters...
|
|
492
|
+
var seen = new Set()
|
|
493
|
+
while(proto != null){
|
|
494
|
+
Object.entries(Object.getOwnPropertyDescriptors(proto))
|
|
495
|
+
.forEach(function([key, value]){
|
|
496
|
+
// skip overloaded keys...
|
|
497
|
+
if(seen.has(key)){
|
|
498
|
+
return }
|
|
499
|
+
// skip non-functions...
|
|
500
|
+
if(typeof(value.value) != 'function'){
|
|
501
|
+
return }
|
|
502
|
+
// skip non-enumerable except for Object.prototype.run(..)...
|
|
503
|
+
if(!(key == 'run'
|
|
504
|
+
&& Object.prototype.run === value.value)
|
|
505
|
+
&& !value.enumerable){
|
|
506
|
+
return }
|
|
507
|
+
// proxy...
|
|
508
|
+
obj[key] = function(...args){
|
|
509
|
+
// XXX should we also .catch(..) here???
|
|
510
|
+
return context.then(function(res){
|
|
511
|
+
return res[key](...args) }) } })
|
|
512
|
+
proto = proto.__proto__ }
|
|
513
|
+
return obj },
|
|
514
|
+
})
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
//---------------------------------------------------------------------
|
|
519
|
+
|
|
520
|
+
var PromiseMixin =
|
|
521
|
+
module.PromiseMixin =
|
|
522
|
+
object.Mixin('PromiseMixin', 'soft', {
|
|
523
|
+
iter: IterablePromise,
|
|
524
|
+
interactive: InteractivePromise,
|
|
525
|
+
cooperative: CooperativePromise,
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
PromiseMixin(Promise)
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
// XXX EXPEREMENTAL...
|
|
532
|
+
var PromiseProtoMixin =
|
|
533
|
+
module.PromiseProtoMixin =
|
|
534
|
+
object.Mixin('PromiseProtoMixin', 'soft', {
|
|
535
|
+
as: ProxyPromise,
|
|
536
|
+
|
|
537
|
+
// XXX
|
|
538
|
+
iter: function(){
|
|
539
|
+
return IterablePromise(this) },
|
|
540
|
+
})
|
|
541
|
+
|
|
542
|
+
PromiseProtoMixin(Promise.prototype)
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
/**********************************************************************
|
|
548
|
+
* vim:set ts=4 sw=4 : */ return module })
|
package/README.md
CHANGED
|
@@ -70,10 +70,16 @@ Library of JavaScript type extensions, types and utilities.
|
|
|
70
70
|
- [`<promise-coop>.then(..)`](#promise-coopthen)
|
|
71
71
|
- [Promise iteration](#promise-iteration)
|
|
72
72
|
- [`Promise.iter(..)` / `promise.IterablePromise(..)`](#promiseiter--promiseiterablepromise)
|
|
73
|
+
- [`<promise>.iter()`](#promiseiter)
|
|
74
|
+
- [`<promise-iter>.iter()`](#promise-iteriter)
|
|
73
75
|
- [`<promise-iter>.map(..)` / `<promise-iter>.filter(..)` / `<promise-iter>.reduce(..)`](#promise-itermap--promise-iterfilter--promise-iterreduce)
|
|
74
76
|
- [`<promise-iter>.flat(..)`](#promise-iterflat)
|
|
77
|
+
- [`<promise-iter>.reverse()`](#promise-iterreverse)
|
|
75
78
|
- [`<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`](#promise-iterthen--promise-itercatch--promise-iterfinally)
|
|
76
79
|
- [Advanced handler](#advanced-handler)
|
|
80
|
+
- [Promise proxies](#promise-proxies)
|
|
81
|
+
- [`<promise>.as(..)`](#promiseas)
|
|
82
|
+
- [`<promise-proxy>.<method>(..)`](#promise-proxymethod)
|
|
77
83
|
- [Generator extensions and utilities](#generator-extensions-and-utilities)
|
|
78
84
|
- [The basics](#the-basics)
|
|
79
85
|
- [`generator.Generator`](#generatorgenerator)
|
|
@@ -1449,8 +1455,8 @@ promise, and it is similar to a _generator_ in that it allows iteration over the
|
|
|
1449
1455
|
contained values and chaining of operations but unlike `Promise.all(..)` this
|
|
1450
1456
|
iteration occurs depth-first instead of breadth first.
|
|
1451
1457
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1458
|
+
One can think of _promise iterators_ vs. _generators_ as the former being
|
|
1459
|
+
internally controlled and asynchronous while the later being externally
|
|
1454
1460
|
controlled and synchronous.
|
|
1455
1461
|
|
|
1456
1462
|
Here is a traditional example using `Promise.all(..)`:
|
|
@@ -1512,8 +1518,32 @@ XXX should we support infinite generators as input?
|
|
|
1512
1518
|
#### `Promise.iter(..)` / `promise.IterablePromise(..)`
|
|
1513
1519
|
|
|
1514
1520
|
Create an _iterable promise_
|
|
1521
|
+
|
|
1515
1522
|
```bnf
|
|
1516
1523
|
Promise.iter(<array>)
|
|
1524
|
+
Promise.iter(<promise>)
|
|
1525
|
+
-> <promise-iter>
|
|
1526
|
+
```
|
|
1527
|
+
|
|
1528
|
+
#### `<promise>.iter()`
|
|
1529
|
+
|
|
1530
|
+
Wrap a promise in an promise iterator.
|
|
1531
|
+
|
|
1532
|
+
```bnf
|
|
1533
|
+
<promise>.iter()
|
|
1534
|
+
-> <promise-iter>
|
|
1535
|
+
```
|
|
1536
|
+
|
|
1537
|
+
If `<promise>` resolves to a non-array value it will be treated as a single
|
|
1538
|
+
element, otherwise the array will be iterated over.
|
|
1539
|
+
|
|
1540
|
+
|
|
1541
|
+
#### `<promise-iter>.iter()`
|
|
1542
|
+
|
|
1543
|
+
Return a shallow copy of the current promise iterator.
|
|
1544
|
+
|
|
1545
|
+
```bnf
|
|
1546
|
+
<promise-iter>.iter()
|
|
1517
1547
|
-> <promise-iter>
|
|
1518
1548
|
```
|
|
1519
1549
|
|
|
@@ -1542,7 +1572,7 @@ and [`.reduce(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe
|
|
|
1542
1572
|
|
|
1543
1573
|
```bnf
|
|
1544
1574
|
<promise-iter>.reduce(<handler>, <state>)
|
|
1545
|
-
-> <promise
|
|
1575
|
+
-> <promise>
|
|
1546
1576
|
|
|
1547
1577
|
<handler>(<state>, <elem>)
|
|
1548
1578
|
-> <state>
|
|
@@ -1555,6 +1585,15 @@ Note that these are different to `Array`'s equivalents in some details:
|
|
|
1555
1585
|
this is because the index with _out-of-order_ and _depth-first_ execution the
|
|
1556
1586
|
index is unknowable and the container is a promise/black-box.
|
|
1557
1587
|
|
|
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.
|
|
1590
|
+
|
|
1591
|
+
`.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.
|
|
1593
|
+
|
|
1594
|
+
Note that since `.reduce(..)` order can not be guaranteed there is no point
|
|
1595
|
+
in implementing `.reduceRigth(..)`.
|
|
1596
|
+
|
|
1558
1597
|
|
|
1559
1598
|
#### `<promise-iter>.flat(..)`
|
|
1560
1599
|
|
|
@@ -1567,6 +1606,16 @@ Note that these are different to `Array`'s equivalents in some details:
|
|
|
1567
1606
|
This is similar to [`<array>.flat(..)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) see it for more info.
|
|
1568
1607
|
|
|
1569
1608
|
|
|
1609
|
+
#### `<promise-iter>.reverse()`
|
|
1610
|
+
|
|
1611
|
+
```bnf
|
|
1612
|
+
<promise-iter>.reverse()
|
|
1613
|
+
-> <promise-iter>
|
|
1614
|
+
```
|
|
1615
|
+
|
|
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.
|
|
1617
|
+
|
|
1618
|
+
|
|
1570
1619
|
#### `<promise-iter>.then(..)` / `<promise-iter>.catch(..)` / `<promise-iter>.finally(..)`
|
|
1571
1620
|
|
|
1572
1621
|
An extension to
|
|
@@ -1621,6 +1670,56 @@ var p = Promise.iter(
|
|
|
1621
1670
|
```
|
|
1622
1671
|
|
|
1623
1672
|
|
|
1673
|
+
### Promise proxies
|
|
1674
|
+
|
|
1675
|
+
_Promise proxies_ generate a set of prototype methods returning promises that when the parent promise is resolved will resolve to a specific method call.
|
|
1676
|
+
|
|
1677
|
+
Example:
|
|
1678
|
+
```javascript
|
|
1679
|
+
var o = {
|
|
1680
|
+
method: function(...args){
|
|
1681
|
+
console.log('method:', ...args)
|
|
1682
|
+
},
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
var p = Peomise.cooperative().as(o)
|
|
1686
|
+
|
|
1687
|
+
p.method(1, 2, 3) // returns a promise...
|
|
1688
|
+
|
|
1689
|
+
// ...
|
|
1690
|
+
|
|
1691
|
+
// resolving a promise will trigger all the proxy emthod execution, so
|
|
1692
|
+
// here 'method: 1, 2, 3' will get printed...
|
|
1693
|
+
p.set(o)
|
|
1694
|
+
|
|
1695
|
+
```
|
|
1696
|
+
|
|
1697
|
+
#### `<promise>.as(..)`
|
|
1698
|
+
|
|
1699
|
+
Create a promise proxy
|
|
1700
|
+
|
|
1701
|
+
```bnf
|
|
1702
|
+
<promise>.as(<object>)
|
|
1703
|
+
<promise>.as(<constructor>)
|
|
1704
|
+
-> <promise-proxy>
|
|
1705
|
+
```
|
|
1706
|
+
|
|
1707
|
+
A proxy promise will be populated with proxy methods to all the methods of the `<object>` or `<constructor>.prototype`.
|
|
1708
|
+
|
|
1709
|
+
#### `<promise-proxy>.<method>(..)`
|
|
1710
|
+
|
|
1711
|
+
When `<promise>` resolves, call the `.<method>(..)` on the resolved value.
|
|
1712
|
+
|
|
1713
|
+
```bnf
|
|
1714
|
+
<promise-proxy>.<method>(..)
|
|
1715
|
+
-> <method-promise>
|
|
1716
|
+
```
|
|
1717
|
+
|
|
1718
|
+
`<method-promise>` will resolve the the return value of the `<method>` when
|
|
1719
|
+
the main `<promise>` is resolved.
|
|
1720
|
+
|
|
1721
|
+
|
|
1722
|
+
|
|
1624
1723
|
## Generator extensions and utilities
|
|
1625
1724
|
|
|
1626
1725
|
```javascript
|
package/RegExp.js
CHANGED
package/generator.js
CHANGED