mirror of
				https://github.com/flynx/pWiki.git
				synced 2025-10-29 18:10:09 +00:00 
			
		
		
		
	
		
			
	
	
		
			158 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			158 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | /********************************************************************** | ||
|  | *  | ||
|  | * 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 }) |