From ada754b7f2cc90ba2765ac06d5003366b805cef0 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Wed, 8 Feb 2023 01:48:59 +0300 Subject: [PATCH] more refactoring and cleanup... Signed-off-by: Alex A. Naanou --- Promise.js | 80 +++++++++++++++++++++++++++++++++++++++------------- generator.js | 16 +++++++++++ package.json | 2 +- test.js | 67 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 135 insertions(+), 30 deletions(-) diff --git a/Promise.js b/Promise.js index cd76c50..4aefe0f 100644 --- a/Promise.js +++ b/Promise.js @@ -117,11 +117,6 @@ module.packed = && Symbol.asyncIterator in list)){ return list .then(this.pack.bind(this)) } - // list: generator... - if(typeof(list) == 'object' - && !list.map - && Symbol.iterator in list){ - list = [...list] } /* XXX on one hand this should be here and on the other I'm not // sure how are we going to thread handler and onerror to // here... @@ -419,6 +414,17 @@ object.Constructor('IterablePromise', Promise, { // handle iterable promise... if(list instanceof IterablePromise){ return this.__handle(list.__packed, handler, onerror) } + // list: generator... + if(typeof(list) == 'object' + // XXX this will cause a break later on... + //&& !list.map + && Symbol.iterator in list){ + try{ + list = [...list] + } catch(err){ + if(typeof(onerror) == 'function'){ + return onerror(err) } + throw err } } // handle promise / async-iterator... if(typeof(list) == 'object' && Symbol.asyncIterator in list){ @@ -429,6 +435,7 @@ object.Constructor('IterablePromise', Promise, { // do the packing... var packed = module.packed.pack(list) + // handle if needed... return handler ? this.__handle(packed, handler, onerror) @@ -753,16 +760,28 @@ object.Constructor('IterablePromise', Promise, { : this.constructor(this.__packed, 'raw') }, // XXX EXPEREMENTAL + // XXX handle rejected state... isSync: function(){ - return !(this.__packed instanceof Promise - || this.__packed - .filter(function(e){ - return e instanceof IterablePromise ? - !e.isSync() - : e instanceof Promise - && !(e instanceof SyncPromise) }) - .length > 0) }, + return '__value' in this + || (this.__packed instanceof Array + && !(this.__packed + .filter(function(e){ + return e instanceof IterablePromise ? + !e.isSync() + : e instanceof Promise + && !(e instanceof SyncPromise) }) + .length > 0)) }, + // XXX BUG: if sync is called before .__handle(..) is done it will + // do things that we do not want yet like unwinding generators + // etc... sync: function(error=false){ + if('__value' in this){ + return this.__value } + if(!this.isSync()){ + return error ? + this.catch(error) + : this } + // try and unpack... try{ var res = this.__unpack() }catch(err){ @@ -834,11 +853,26 @@ object.Constructor('IterablePromise', Promise, { // populate new instance... if(promise){ + // XXX EXPEREMENTAL... + obj.then(function(value){ + Object.defineProperty(obj, '__value', { + value, + enumerable: false, + }) }) + // handle onerror(..) + var error = false var handleError = function(err){ - onerror ? - promise.resolve(onerror(err)) - : promise.reject(err) } + error = true + if(onerror){ + var res = onerror(err) + // XXX do we use .__pack(..) here??? + obj.__packed = undefined + // XXX this is wrong -- need to store the value as-is... + //obj.__packed = [res] + promise.resolve(res) + } else { + promise.reject(err) } } // handle/pack input data... if(handler != 'raw'){ //list = list instanceof IterablePromise ? @@ -852,6 +886,10 @@ object.Constructor('IterablePromise', Promise, { writable: true, }) + // list generator broke... + if(error){ + return obj } + // handle promise state... try{ var res = obj.__unpack(list) @@ -939,18 +977,20 @@ object.Constructor('IterableSequentialStartPromise', IterablePromise, { res.push(e) } return res } - // NOTE: we are not handling the list here... - list = object.parentCall(IterableSequentialStartPromise.prototype.__pack, this, list) + // NOTE: we are not handling the list here yet... + // NOTE: if packing breaks but the error is handled this will return undefined... + list = object.parentCall(IterableSequentialStartPromise.prototype.__pack, this, + list, undefined, onerror) list = list instanceof SyncPromise ? list.sync() : list // repack... list = list instanceof Array ? repack(list) - : list.then ? + : list && list.then ? list.then(repack) : list - return handler ? + return list && handler ? this.__handle(list, handler, onerror) : list }, }) diff --git a/generator.js b/generator.js index dd9ca41..1437557 100644 --- a/generator.js +++ b/generator.js @@ -236,6 +236,14 @@ object.Mixin('GeneratorMixin', 'soft', { reduce: makeGenerator('reduce'), reduceRight: makeGenerator('reduceRight'), + // XXX + smap: makeGenerator('smap'), + sfilter: makeGenerator('sfilter'), + sreduce: makeGenerator('sreduce'), + sreduceRight: makeGenerator('sreduceRight'), + sforEach: makeGenerator('sforEach'), + //*/ + between: makeGenerator('between'), // XXX EXPERIMENTAL @@ -413,6 +421,8 @@ object.Mixin('GeneratorProtoMixin', 'soft', { for(var e of this){ yield func(e, i++, this) } } }, __onstop), + smap: function*(func){ + yield* this.map(...arguments) }, filter: stoppable( function*(func){ var i = 0 @@ -428,6 +438,8 @@ object.Mixin('GeneratorProtoMixin', 'soft', { err.value = e } throw err } }, __onstop), + sfilter: function*(func){ + yield* this.filter(...arguments) }, reduce: stoppable( function(func, res){ @@ -439,6 +451,8 @@ object.Mixin('GeneratorProtoMixin', 'soft', { // was passed a function from ever being treated as onstop(..)... function(res, f, _, onstop){ return __onstop.call(this, res, onstop) }), + sreduce: function*(func, res){ + yield* this.reduce(...arguments) }, greduce: function*(func, res){ yield this.reduce(...arguments) }, @@ -463,6 +477,8 @@ object.Mixin('GeneratorProtoMixin', 'soft', { // XXX EXPERIMENTAL forEach: function(func){ return [...this].map(func) }, + sforEach: function(func){ + return this.forEach(func) }, pop: function(){ return [...this].pop() }, diff --git a/package.json b/package.json index ea4471b..dfca9ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ig-types", - "version": "6.25.1", + "version": "6.25.3", "description": "Generic JavaScript types and type extensions...", "main": "main.js", "scripts": { diff --git a/test.js b/test.js index 3fac3ed..e9d2858 100755 --- a/test.js +++ b/test.js @@ -304,7 +304,7 @@ var cases = test.Cases({ 'promises as elements') // XXX split this into separate cases... - for(var meth of ['iter', 'seqiter']){ + for(var meth of ['iter', 'seqiter', 'seqstartiter']){ // XXX need a recursive assert... var should_be = [ [1], [2], [3], [4], [5], [6] ] var got = await Promise[meth]([ @@ -336,6 +336,12 @@ var cases = test.Cases({ await Promise[meth]([1, Promise.resolve(2), Promise.resolve(3)]), [1,2,3], 'flat unpack', meth) + + assert.array( + await Promise[meth]( + (function*(){ yield* [1, Promise.resolve(2), Promise.resolve(3)] })()), + [1,2,3], + 'generator input', meth) } var order = [] @@ -457,7 +463,8 @@ var cases = test.Cases({ // error... for(var iter of ['iter', 'seqiter', 'seqstartiter']){ assert( - await Promise[iter]([1,2,Promise.resolve(3),4,5], + await Promise[iter]( + [1,2,Promise.resolve(3),4,5], function(e){ if(e == 2){ throw 'ERROR' } @@ -467,7 +474,8 @@ var cases = test.Cases({ == 'done', `.${iter}(..): .catch(..)`) assert( - await Promise[iter]([1,2,Promise.resolve(3),4,5], + await Promise[iter]( + [1,2,Promise.resolve(3),4,5], function(e){ if(e == 2){ throw 'ERROR' } @@ -477,7 +485,8 @@ var cases = test.Cases({ == 'done', `.${iter}(..): onerror(..)`) assert( - await Promise[iter]([1,2,Promise.resolve(3),4,5], + await Promise[iter]( + [1,2,Promise.resolve(3),4,5], function(e){ if(e == 3){ throw 'ERROR' } @@ -487,7 +496,8 @@ var cases = test.Cases({ == 'done', `.${iter}(..): edge onerror(..)`) assert( - await Promise[iter]([1,2,Promise.resolve(3),4,5], + await Promise[iter]( + [1,2,Promise.resolve(3),4,5], function(e){ if(e == 4){ throw 'ERROR' } @@ -499,17 +509,56 @@ var cases = test.Cases({ assert( await Promise[iter]( (function*(){ - yield* [1,2,3] - throw 'ERROR' })(), + yield* [1,2,3] })(), function(e){ - if(e == 4){ + if(e == 2){ throw 'ERROR' } return e }, function(err){ return 'done' }) == 'done', - `.${iter}(..): late onerror(..)`) + `.${iter}(..): input generator, onerror(..) in handler`) + assert( + (pr = await Promise[iter]( + (function*(){ + yield* [1,2,3] + throw 'ERROR' })(), + function(e){ + return e }, + function(err){ + return 'done' })) + == 'done', + `.${iter}(..): onerror(..) in input generator`, pr) + assert( + await (pr = Promise[iter]( + (function*(){ + yield* [1,2,3] + throw 'ERROR' })(), + function(e){ + if(e == 4){ + throw 'ERROR' } + return e }, + function(err){ + return 'done' }) + .sync()) + === 'done', + `.${iter}(..): onerror(..) on input generator + .sync()`, pr) + assert( + await Promise.iter( + (function*(){ + yield* [1,2,3] + throw 'ERROR' })(), + function(e){ + return new Promise(function(ok, err){ + if(e == 2){ + err('moo!') } + ok(e) })}, + function(err){ + return 333 }) + == 333, + `.${iter}(..): onerror(..) with promise handler`) } + }, // Date.js