pWiki/lib/stoppable.js
Alex A. Naanou 2b58903675 npm update + tweaks...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2022-08-03 01:57:57 +03:00

158 lines
4.0 KiB
JavaScript
Executable File

/**********************************************************************
*
* 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 AsyncFunction =
(async function(){}).constructor
var Generator =
(function*(){}).constructor
var AsyncGenerator =
(async function*(){}).constructor
//---------------------------------------------------------------------
// 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...
module =
function(func){
return Object.assign(
// NOTE: the below implementations are almost the same, the main
// differences being the respective generator/async mechanics...
func instanceof Generator ?
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 ?
async function*(){
try{
for await(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 AsyncFunction ?
async function(){
try{
var res = await 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 } }
: 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() }, }) }
//---------------------------------------------------------------------
module.STOP =
function(value){
return {
__proto__: module.STOP.prototype,
doc: 'stop iteration.',
value,
} }
/**********************************************************************
* vim:set ts=4 sw=4 nowrap : */ return module })