initial code migrated from object.js...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-07-05 23:00:51 +03:00
parent 156e4b1704
commit 777bc53dd0
2 changed files with 163 additions and 0 deletions

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "ig-stoppable",
"version": "1.0.0",
"description": "Utility library implementing tooling to make stoppable functions...",
"main": "stoppable.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/flynx/stoppable.js.git"
},
"author": "Alex A. Naanou",
"license": "BSD-3-Clause",
"bugs": {
"url": "https://github.com/flynx/stoppable.js/issues"
},
"homepage": "https://github.com/flynx/stoppable.js#readme"
}

144
stoppable.js Normal file
View File

@ -0,0 +1,144 @@
/**********************************************************************
*
* stoppable.js
*
* Utility library implementing tooling to make stoppable functions...
*
*
* Repo and docs:
* https://github.com/flynx/stoppable.js
*
*
***********************************************/ /* c8 ignore next 2 */
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
(function(require){ var module={} // make module AMD/node compatible...
/*********************************************************************/
//---------------------------------------------------------------------
// helpers...
var Generator =
(function*(){}).constructor
var AsyncGenerator =
(async function*(){}).constructor
//---------------------------------------------------------------------
var STOP =
module.STOP =
function(value){
return {
__proto__: STOP.prototype,
doc: 'stop iteration.',
value,
} }
//---------------------------------------------------------------------
// Wrap a callable in a STOP handler
//
// stoppable(func)
// -> func
//
// stoppable(gen)
// -> gen
//
// stoppable(asyncgen)
// -> asyncgen
//
//
// The client callable can be one of:
// - function
// - generator
// - async generator
//
// The returned callable will be of the same type as the input callable.
//
// The wrapper handles STOP slightly differently if the client is a
// function or if it is a generator / async generator:
// - function
// STOP returned / thrown
// -> return undefined
// STOP(value) returned / thrown
// -> return value
// - generator / async generator
// STOP yielded / thrown
// -> iteration stops
// STOP(value) yielded / thrown
// -> value yielded and iteration stops
//
//
// NOTE: this repeats the same code at lest twice, not sure yet how to avoid
// this...
var stoppable =
module.stoppable =
function(func){
return Object.assign(
func instanceof Generator ?
// NOTE: the only difference between Generator/AsyncGenerator
// versions of this is the async keyword -- keep them
// in sync...
function*(){
try{
for(var res of func.call(this, ...arguments)){
if(res === module.STOP){
return }
if(res instanceof module.STOP){
yield res.value
return }
yield res }
} catch(err){
if(err === module.STOP){
return
} else if(err instanceof module.STOP){
yield err.value
return }
throw err } }
: func instanceof AsyncGenerator ?
// NOTE: the only difference between Generator/AsyncGenerator
// versions of this is the async keyword -- keep them
// in sync...
async function*(){
try{
for(var res of func.call(this, ...arguments)){
if(res === module.STOP){
return }
if(res instanceof module.STOP){
yield res.value
return }
yield res }
} catch(err){
if(err === module.STOP){
return
} else if(err instanceof module.STOP){
yield err.value
return }
throw err } }
: function(){
try{
var res = func.call(this, ...arguments)
// NOTE: this is here for uniformity...
if(res === module.STOP){
return }
if(res instanceof module.STOP){
return res.value }
return res
} catch(err){
if(err === module.STOP){
return
} else if(err instanceof module.STOP){
return err.value }
throw err } },
{ toString: function(){
return func.toString() }, }) }
/**********************************************************************
* vim:set ts=4 sw=4 nowrap : */ return module })