added onstop(..) callback to all stoppable funcs...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-12-29 03:34:31 +03:00
parent 47c10ea0b1
commit 9815415827
4 changed files with 147 additions and 116 deletions

View File

@ -524,19 +524,27 @@ object.Mixin('ArrayProtoMixin', 'soft', {
// XXX this should handle throwing STOP!!!
// ...might also ne a good idea to isolate the STOP mechanics
// into a spearate module/package...
iter: stoppable(function*(handler=undefined){
if(handler){
var i = 0
for(var e of this){
var res = handler.call(this, e, i++)
// treat non-iterables as single elements...
if(typeof(res) == 'object'
&& Symbol.iterator in res){
yield* res
} else {
yield res } }
} else {
yield* this }}),
iter: stoppable(
function*(handler=undefined, onstop){
if(handler){
var i = 0
for(var e of this){
var res = handler.call(this, e, i++)
// treat non-iterables as single elements...
if(typeof(res) == 'object'
&& Symbol.iterator in res){
yield* res
} else {
yield res } }
} else {
yield* this }},
// handle stops is onstop(..) is defined...
function(res, _, onstop){
typeof(onstop) == 'function'
&& onstop.call(this,
...(res === STOP ?
[]
: [res])) }),
// Stoppable iteration...

View File

@ -255,16 +255,6 @@ object.Constructor('IterablePromise', Promise, {
return elem })
.flat() },
/*/
// XXX BUG:
// await Promise.iter([Promise.all([1,2,3])], e => e)
// await Promise.iter([Promise.iter([1,2,3])], e => e)
// -> [1]
// the issue is in .__handle(..)'s
// elem = elem instanceof Promise ?
// elem.then(function([e]){
// // XXX
// return e })
// : ...
__pack: function(list, handler=undefined, onerror=undefined){
var that = this
// handle iterator...
@ -315,6 +305,7 @@ object.Constructor('IterablePromise', Promise, {
this.__handle(list, handler, onerror)
: list },
// transform/handle packed array (sync, but can return promises in the list)...
// XXX need a strict spec...
__handle: function(list, handler=undefined, onerror=undefined){
var that = this
if(typeof(list) == 'function'){
@ -335,17 +326,20 @@ object.Constructor('IterablePromise', Promise, {
: 'map'
return list
[map](function(elem){
// XXX need a strict spec...
return elem instanceof IterablePromise ?
// XXX should this be expanded??? (like Array below)
(elem.isSync() ?
handler(elem.sync())
// XXX need to handle this but keep it IterablePromise...
: elem.iterthen(handler))
: (elem instanceof SyncPromise
&& !(elem.sync() instanceof Promise)) ?
// XXX should this be expanded??? (like Array below)
handler(elem.sync())
// promise / promise-like...
: elem && elem.then ?
// XXX handle STOP...
// XXX handle STOP -- no need to call handlers after a STOP...
// ...is there a way to detect STOP from inside .smap(..) ???
elem.then(function(elem){
return handler(
elem.length == 1 ?

View File

@ -91,23 +91,36 @@ function*(lst=[]){
} else {
yield lst } }
// handle stops is onstop(..) is defined...
var __onstop =
function(res, _, ...args){
var onstop = args.at(-1)
typeof(onstop) == 'function'
&& onstop.call(this,
...(res === STOP ?
[]
: [res])) }
// XXX updatae Array.js' version for compatibility...
// XXX DOCS!!!
var iter =
module.iter =
Generator.iter =
stoppable(function(lst=[]){
// handler -> generator-constructor...
if(typeof(lst) == 'function'){
// we need to be callable...
var that = this instanceof Function ?
this
// generic root generator...
: module.__iter
return function*(){
yield* that(...arguments).iter(lst) } }
// no handler -> generator instance...
return module.__iter(lst) })
stoppable(
function(lst=[]){
// handler -> generator-constructor...
if(typeof(lst) == 'function'){
// we need to be callable...
var that = this instanceof Function ?
this
// generic root generator...
: module.__iter
return function*(){
yield* that(...arguments).iter(lst) } }
// no handler -> generator instance...
return module.__iter(lst) },
__onstop)
// NOTE: we need .iter(..) to both return generators if passed an iterable
// and genereator constructos if passed a function...
@ -308,31 +321,33 @@ var GeneratorProtoMixin =
module.GeneratorProtoMixin =
object.Mixin('GeneratorProtoMixin', 'soft', {
// XXX use module.iter(..) ???
iter: stoppable(function*(handler, onerror){
try{
if(handler){
var i = 0
for(var elem of this){
var res = handler.call(this, elem, i)
// expand iterables...
if(typeof(res) == 'object'
&& Symbol.iterator in res){
yield* res
// as-is...
} else {
yield res }}
// no handler...
} else {
yield* this }
}catch(err){
if(onerror){
if(!(err === STOP
|| err instanceof STOP)){
var res = onerror(err)
if(res){
yield res
return } } }
throw err }}),
iter: stoppable(
function*(handler, onerror){
try{
if(handler){
var i = 0
for(var elem of this){
var res = handler.call(this, elem, i)
// expand iterables...
if(typeof(res) == 'object'
&& Symbol.iterator in res){
yield* res
// as-is...
} else {
yield res }}
// no handler...
} else {
yield* this }
}catch(err){
if(onerror){
if(!(err === STOP
|| err instanceof STOP)){
var res = onerror(err)
if(res){
yield res
return } } }
throw err }},
__onstop),
//*/
at: function(i){
@ -396,8 +411,10 @@ object.Mixin('GeneratorProtoMixin', 'soft', {
yield* func(e, i++, this) }
} else {
for(var e of this){
yield func(e, i++, this) } } }),
filter: stoppable(function*(func){
yield func(e, i++, this) } } },
__onstop),
filter: stoppable(
function*(func){
var i = 0
try{
for(var e of this){
@ -409,28 +426,36 @@ object.Mixin('GeneratorProtoMixin', 'soft', {
if(!err.value){
throw STOP }
err.value = e }
throw err } }),
throw err } },
__onstop),
reduce: stoppable(function(func, res){
var i = 0
for(var e of this){
res = func(res, e, i++, this) }
return res }),
reduce: stoppable(
function(func, res){
var i = 0
for(var e of this){
res = func(res, e, i++, this) }
return res },
// NOTE: we need to wrap __onstop(..) here to prevent res if it
// was passed a function from ever being treated as onstop(..)...
function(res, f, _, onstop){
return __onstop.call(this, res, onstop) }),
greduce: function*(func, res){
yield this.reduce(...arguments) },
between: stoppable(function*(func){
var i = 0
var j = 0
var prev
for(var e of this){
if(i > 0){
yield typeof(func) == 'function' ?
func.call(this, [prev, e], i-1, i + j++, this)
: func }
prev = e
yield e
i++ } }),
between: stoppable(
function*(func){
var i = 0
var j = 0
var prev
for(var e of this){
if(i > 0){
yield typeof(func) == 'function' ?
func.call(this, [prev, e], i-1, i + j++, this)
: func }
prev = e
yield e
i++ } },
__onstop),
// NOTE: this is a special case in that it will unwind the generator...
// NOTE: this is different from <array>.forEach(..) in that this will
@ -566,29 +591,31 @@ object.Mixin('AsyncGeneratorProtoMixin', 'soft', {
return this.unwind.finally(...arguments) },
// XXX might be a good idea to use this approach above...
iter: stoppable(async function*(handler=undefined, onerror=undefined){
try{
var i = 0
if(handler){
for await(var e of this){
var res = handler.call(this, e, i++)
if(typeof(res) == 'object'
&& Symbol.iterator in res){
yield* res
} else {
yield res } }
} else {
yield* this }
}catch(err){
if(onerror){
if(!(err === STOP || err instanceof STOP)){
var res = onerror(err)
if(res !== undefined){
yield handler ?
handler(res)
: res }
return } }
throw err } }),
iter: stoppable(
async function*(handler=undefined, onerror=undefined){
try{
var i = 0
if(handler){
for await(var e of this){
var res = handler.call(this, e, i++)
if(typeof(res) == 'object'
&& Symbol.iterator in res){
yield* res
} else {
yield res } }
} else {
yield* this }
}catch(err){
if(onerror){
if(!(err === STOP || err instanceof STOP)){
var res = onerror(err)
if(res !== undefined){
yield handler ?
handler(res)
: res }
return } }
throw err } },
__onstop),
map: async function*(func){
yield* this.iter(function(elem, i){
@ -686,9 +713,11 @@ function*(value=true, stop){
var produce =
module.produce =
stoppable(function*(func){
while(true){
yield func() } })
stoppable(
function*(func){
while(true){
yield func() } },
__onstop)

16
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "ig-types",
"version": "6.24.10",
"version": "6.24.11",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ig-types",
"version": "6.24.10",
"version": "6.24.11",
"license": "BSD-3-Clause",
"dependencies": {
"ig-object": "^6.0.0",
@ -354,9 +354,9 @@
}
},
"node_modules/ig-stoppable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ig-stoppable/-/ig-stoppable-2.0.1.tgz",
"integrity": "sha512-vos7eFNHryIg6yNzrWTV1QP1Sja5JkMU3nL2Y/YvSgU74l7w1Rx6yfVKoEHwNOex4MCkLsq6wMa91Ac6IWOtIA=="
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/ig-stoppable/-/ig-stoppable-2.0.4.tgz",
"integrity": "sha512-KxS8AGsjelRAmbbQuASj+XRuk99P4OOprd+lIUMU2nuRKPQItNQK/apls8IlR3kNp5ZdQqBdV+zVJmYGrxofnA=="
},
"node_modules/ig-test": {
"version": "1.5.4",
@ -1073,9 +1073,9 @@
}
},
"ig-stoppable": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ig-stoppable/-/ig-stoppable-2.0.1.tgz",
"integrity": "sha512-vos7eFNHryIg6yNzrWTV1QP1Sja5JkMU3nL2Y/YvSgU74l7w1Rx6yfVKoEHwNOex4MCkLsq6wMa91Ac6IWOtIA=="
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/ig-stoppable/-/ig-stoppable-2.0.4.tgz",
"integrity": "sha512-KxS8AGsjelRAmbbQuASj+XRuk99P4OOprd+lIUMU2nuRKPQItNQK/apls8IlR3kNp5ZdQqBdV+zVJmYGrxofnA=="
},
"ig-test": {
"version": "1.5.4",