mirror of
				https://github.com/flynx/pWiki.git
				synced 2025-10-31 19:10:08 +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 })
 |