mirror of
				https://github.com/flynx/pWiki.git
				synced 2025-11-04 13:00:10 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			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 })
 |