| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							| 
									
										
										
										
											2020-05-02 00:41:33 +03:00
										 |  |  | * object.js | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | * This is a set of tools and abstractions to create and manage  | 
					
						
							|  |  |  | * constructors, objects and prototype chains in idiomatic JavaScript. | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | * | 
					
						
							| 
									
										
										
										
											2020-05-09 04:50:22 +03:00
										 |  |  | * Motivation: | 
					
						
							|  |  |  | * 	This package was originally written to unify low level object  | 
					
						
							|  |  |  | * 	definitios within a large project and from there evolved to be a  | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | * 	full functional alternative to the ES6 class notation with all of  | 
					
						
							|  |  |  | * 	its inconsistencies, hoops, "the same but slightly different" ways  | 
					
						
							|  |  |  | * 	to do things and "magic" (hidden) functionality. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * Repo and docs: | 
					
						
							|  |  |  | * 	https://github.com/flynx/object.js
 | 
					
						
							| 
									
										
										
										
											2020-05-09 04:50:22 +03:00
										 |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | **********************************************************************/ | 
					
						
							| 
									
										
										
										
											2020-04-29 21:15:46 +03:00
										 |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-08-21 02:27:54 +03:00
										 |  |  | // Helpers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-23 20:12:27 +03:00
										 |  |  | var TAB_SIZE = | 
					
						
							|  |  |  | module.TAB_SIZE = 4 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 15:56:03 +03:00
										 |  |  | var KEEP_INDENT =  | 
					
						
							|  |  |  | module.KEEP_INDENT = 1 | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-23 20:31:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-08 15:53:24 +03:00
										 |  |  | // Normalize code indent...
 | 
					
						
							| 
									
										
										
										
											2020-04-23 20:31:42 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 	normalizeIndent(text)
 | 
					
						
							|  |  |  | // 		-> text
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:31:42 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-23 20:31:42 +03:00
										 |  |  | // This will remove common indent from each like of text, this is useful 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 20:04:42 +03:00
										 |  |  | // for printing function code of functions that were defined at deep 
 | 
					
						
							|  |  |  | // levels of indent.
 | 
					
						
							| 
									
										
										
										
											2020-04-23 20:31:42 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | // This will ignore the indent of the first line.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If the last line is indented higher or equal to the rest of the text 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 15:56:03 +03:00
										 |  |  | // we will user keep_indent (defaults to KEEP_INDENT) to indent the rest 
 | 
					
						
							|  |  |  | // of the text.
 | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | // This will indent the following styles correctnly:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		|function(a, b){				|function(a, b){
 | 
					
						
							|  |  |  | // 		|	return a + b }				|	return a + b
 | 
					
						
							|  |  |  | // 		|								|}
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-30 20:04:42 +03:00
										 |  |  | // NOTE: this will trim out both leading and trailing white-space.
 | 
					
						
							| 
									
										
										
										
											2020-04-25 01:14:00 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2018-08-21 02:27:54 +03:00
										 |  |  | // XXX is this the right place for this???
 | 
					
						
							|  |  |  | // 		...when moving take care that ImageGrid's core.doc uses this...
 | 
					
						
							|  |  |  | var normalizeIndent = | 
					
						
							|  |  |  | module.normalizeIndent = | 
					
						
							| 
									
										
										
										
											2020-06-02 15:56:03 +03:00
										 |  |  | function(text, tab_size, keep_indent){ | 
					
						
							| 
									
										
										
										
											2020-05-08 15:53:24 +03:00
										 |  |  | 	tab_size = tab_size == null ?  | 
					
						
							|  |  |  | 		TAB_SIZE  | 
					
						
							|  |  |  | 		: tab_size | 
					
						
							| 
									
										
										
										
											2020-06-02 15:56:03 +03:00
										 |  |  | 	keep_indent = (keep_indent == null ?  | 
					
						
							|  |  |  | 			KEEP_INDENT  | 
					
						
							|  |  |  | 			: keep_indent)  | 
					
						
							| 
									
										
										
										
											2020-05-08 15:53:24 +03:00
										 |  |  | 		* tab_size | 
					
						
							| 
									
										
										
										
											2020-05-08 18:07:21 +03:00
										 |  |  | 	// prepare text...
 | 
					
						
							|  |  |  | 	var tab = ' '.repeat(tab_size) | 
					
						
							|  |  |  | 	text = tab != '' ? | 
					
						
							|  |  |  | 		text.replace(/\t/g, tab) | 
					
						
							| 
									
										
										
										
											2020-04-23 20:12:27 +03:00
										 |  |  | 		: text | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 	var lines = text.trim().split(/\n/) | 
					
						
							| 
									
										
										
										
											2020-05-08 18:07:21 +03:00
										 |  |  | 	// count common indent...
 | 
					
						
							| 
									
										
										
										
											2018-08-21 02:27:54 +03:00
										 |  |  | 	var l = lines  | 
					
						
							|  |  |  | 		.reduce(function(l, e, i){ | 
					
						
							|  |  |  | 			var indent = e.length - e.trimLeft().length | 
					
						
							|  |  |  | 			return e.trim().length == 0  | 
					
						
							| 
									
										
										
										
											2020-05-08 18:07:21 +03:00
										 |  |  | 						// ignore 0 indent of first line...
 | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 						|| (i == 0 && indent == 0) ? | 
					
						
							|  |  |  | 					l  | 
					
						
							| 
									
										
										
										
											2020-06-02 15:56:03 +03:00
										 |  |  | 				// last line -- ignore keep_indent if lower indent...
 | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 				: i == lines.length-1 && indent > l ?  | 
					
						
							| 
									
										
										
										
											2020-06-02 15:56:03 +03:00
										 |  |  | 					Math.max(l-keep_indent, 0)  | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 				// initial state...
 | 
					
						
							| 
									
										
										
										
											2018-08-21 02:27:54 +03:00
										 |  |  | 				: l < 0 ?  | 
					
						
							|  |  |  | 					indent  | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 				// min...
 | 
					
						
							|  |  |  | 				: Math.min(l, indent) }, -1) | 
					
						
							| 
									
										
										
										
											2020-05-08 18:07:21 +03:00
										 |  |  | 	// normalize...
 | 
					
						
							| 
									
										
										
										
											2018-08-21 02:27:54 +03:00
										 |  |  | 	return lines | 
					
						
							|  |  |  | 		.map(function(line, i){  | 
					
						
							| 
									
										
										
										
											2020-04-23 20:12:27 +03:00
										 |  |  | 			return i == 0 ?  | 
					
						
							|  |  |  | 				line  | 
					
						
							|  |  |  | 				: line.slice(l) }) | 
					
						
							|  |  |  | 		.join('\n') | 
					
						
							|  |  |  | 		.trim() } | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-08 15:53:24 +03:00
										 |  |  | // shorthand more suted for text...
 | 
					
						
							|  |  |  | var normalizeTextIndent = | 
					
						
							|  |  |  | module.normalizeTextIndent = | 
					
						
							| 
									
										
										
										
											2020-06-02 15:56:03 +03:00
										 |  |  | function(text, tab_size, keep_indent){ | 
					
						
							|  |  |  | 	return module.normalizeIndent(text, tab_size, keep_indent || 0) } | 
					
						
							| 
									
										
										
										
											2020-05-08 15:53:24 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | // Match two objects...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:20:20 +03:00
										 |  |  | // 	match(a, b)
 | 
					
						
							|  |  |  | // 		-> bool
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will match objects iff:
 | 
					
						
							|  |  |  | // 	- if they are identical or
 | 
					
						
							|  |  |  | // 	- attr count is the same and,
 | 
					
						
							|  |  |  | // 	- attr names are the same and,
 | 
					
						
							|  |  |  | // 	- attr values are identical.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-06-01 02:49:00 +03:00
										 |  |  | // NOTE: this will do a shallow test using Object.keys(..) thus .__proto__
 | 
					
						
							|  |  |  | // 		attributes are ignored...
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | var match =  | 
					
						
							|  |  |  | module.match = | 
					
						
							|  |  |  | function(base, obj){ | 
					
						
							|  |  |  | 	// identity...
 | 
					
						
							|  |  |  | 	if(base === obj){ | 
					
						
							|  |  |  | 		return true } | 
					
						
							|  |  |  | 	// typeof -- sanity check...
 | 
					
						
							|  |  |  | 	if(typeof(base) != typeof(obj)){ | 
					
						
							|  |  |  | 		return false } | 
					
						
							|  |  |  | 	// attr count...
 | 
					
						
							|  |  |  | 	var o = Object.keys(Object.getOwnPropertyDescriptors(obj)) | 
					
						
							|  |  |  | 	if(Object.keys(Object.getOwnPropertyDescriptors(base)).length != o.length){ | 
					
						
							|  |  |  | 		return false } | 
					
						
							|  |  |  | 	// names and values...
 | 
					
						
							|  |  |  | 	o = o.map(function(k){ | 
					
						
							|  |  |  | 			return [k, obj[k]] }) | 
					
						
							|  |  |  | 	while(o.length > 0){ | 
					
						
							|  |  |  | 		var [k, v] = o.pop() | 
					
						
							|  |  |  | 		if(!base.hasOwnProperty(k) || base[k] !== v){ | 
					
						
							|  |  |  | 			return false } } | 
					
						
							|  |  |  | 	return true } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2020-04-30 19:50:19 +03:00
										 |  |  | // Prototype chain content access...
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | // object to trigger iteration stop...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | module.STOP =  | 
					
						
							|  |  |  | 	{doc: 'stop iteration.'} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // Get a list of source objects for a prop/attr name...
 | 
					
						
							| 
									
										
										
										
											2020-04-15 00:42:20 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 	sources(obj, name)
 | 
					
						
							|  |  |  | // 	sources(obj, name, callback)
 | 
					
						
							|  |  |  | // 		-> list
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // 		-> []
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							| 
									
										
										
										
											2020-05-30 01:17:13 +03:00
										 |  |  | // 	Get callables or objects defining .__call__ (special-case)
 | 
					
						
							|  |  |  | // 	sources(obj, '__call__')
 | 
					
						
							|  |  |  | // 	sources(obj, '__call__', callback)
 | 
					
						
							|  |  |  | // 		-> list
 | 
					
						
							|  |  |  | // 		-> []
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // 	callback(obj)
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | // 		-> STOP
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // 		-> ..
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // The callback(..) is called with each matching object.
 | 
					
						
							| 
									
										
										
										
											2020-04-15 00:42:20 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | // callback(..) return values:
 | 
					
						
							|  |  |  | // 	- STOP			- stop the search and return the match list terminated
 | 
					
						
							|  |  |  | // 						with the object triggering the stop.
 | 
					
						
							|  |  |  | // 	- undefined		- return the triggering object as-is
 | 
					
						
							|  |  |  | // 						NOTE: this is the same as returning [obj]
 | 
					
						
							|  |  |  | // 	- array			- merge array content into the result insteaad of 
 | 
					
						
							|  |  |  | // 						the triggering value.
 | 
					
						
							|  |  |  | // 						NOTE: an ampty array will effectively omit the 
 | 
					
						
							|  |  |  | // 							triggering object from the results.
 | 
					
						
							|  |  |  | // 	- other			- return a value instead of the triggering object.
 | 
					
						
							| 
									
										
										
										
											2020-05-30 01:17:13 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-15 00:42:20 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | // NOTE: this gos up the prototype chain, not caring about any role (
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // 		instance/class or instance/prototype) bounderies and depends 
 | 
					
						
							|  |  |  | // 		only on the object given as the starting point.
 | 
					
						
							|  |  |  | // 		It is possible to start the search from this, thus checking
 | 
					
						
							|  |  |  | // 		for any overloading in the instance, though this approach is 
 | 
					
						
							|  |  |  | // 		not very reusable....
 | 
					
						
							| 
									
										
										
										
											2020-04-30 16:41:19 +03:00
										 |  |  | // NOTE: this will not trigger any props...
 | 
					
						
							| 
									
										
										
										
											2020-04-15 00:42:20 +03:00
										 |  |  | var sources = | 
					
						
							|  |  |  | module.sources = | 
					
						
							| 
									
										
										
										
											2020-04-16 01:49:24 +03:00
										 |  |  | function(obj, name, callback){ | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 	var o | 
					
						
							| 
									
										
										
										
											2020-04-15 00:42:20 +03:00
										 |  |  | 	var res = [] | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 	while(obj != null){ | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 		//if(obj.hasOwnProperty(name)){
 | 
					
						
							|  |  |  | 		if(obj.hasOwnProperty(name)  | 
					
						
							|  |  |  | 				|| (name == '__call__' && typeof(obj) == 'function')){ | 
					
						
							| 
									
										
										
										
											2020-04-15 00:42:20 +03:00
										 |  |  | 			// handle callback...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 			o = callback | 
					
						
							| 
									
										
										
										
											2020-04-16 01:49:24 +03:00
										 |  |  | 				&& callback(obj) | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 			// manage results...
 | 
					
						
							|  |  |  | 			res.push( | 
					
						
							|  |  |  | 				(o === undefined || o === module.STOP) ? | 
					
						
							|  |  |  | 					[obj] | 
					
						
							|  |  |  | 					: o ) | 
					
						
							|  |  |  | 			// stop...
 | 
					
						
							|  |  |  | 			if(o === module.STOP){ | 
					
						
							|  |  |  | 				return res.flat() } } | 
					
						
							|  |  |  | 		obj = obj.__proto__ } | 
					
						
							|  |  |  | 	return res.flat() } | 
					
						
							| 
									
										
										
										
											2020-04-15 00:42:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-23 16:38:43 +03:00
										 |  |  | // Get a list of values/props set in source objects for a prop/attr name...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Get values...
 | 
					
						
							|  |  |  | // 	values(obj, name)
 | 
					
						
							|  |  |  | // 	values(obj, name, callback)
 | 
					
						
							|  |  |  | // 		-> list
 | 
					
						
							|  |  |  | // 		-> []
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							|  |  |  | // 	Get propery descriptors...
 | 
					
						
							|  |  |  | // 	values(obj, name, true)
 | 
					
						
							|  |  |  | // 	values(obj, name, callback, true)
 | 
					
						
							|  |  |  | // 		-> list
 | 
					
						
							|  |  |  | // 		-> []
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | // 	callback(value/prop, obj)
 | 
					
						
							|  |  |  | // 		-> STOP
 | 
					
						
							| 
									
										
										
										
											2020-05-23 16:38:43 +03:00
										 |  |  | // 		-> ..
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-30 01:17:13 +03:00
										 |  |  | // Special case: name is given as '__call__'
 | 
					
						
							|  |  |  | // 		This will return either the value the object if it is callable 
 | 
					
						
							|  |  |  | // 		or the value of .__call__ attribute...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-30 01:17:13 +03:00
										 |  |  | // NOTE: for more docs on the callback(..) see sources(..)
 | 
					
						
							| 
									
										
										
										
											2020-05-23 16:38:43 +03:00
										 |  |  | var values = | 
					
						
							|  |  |  | module.values = | 
					
						
							|  |  |  | function(obj, name, callback, props){ | 
					
						
							|  |  |  | 	props = callback === true ?  | 
					
						
							|  |  |  | 		callback  | 
					
						
							|  |  |  | 		: props | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	var _get = function(obj, name){ | 
					
						
							|  |  |  | 		return props ? | 
					
						
							|  |  |  | 				Object.getOwnPropertyDescriptor(obj, name) | 
					
						
							|  |  |  | 			// handle callable instance...
 | 
					
						
							|  |  |  | 			: !(name in obj)  | 
					
						
							|  |  |  | 					&& name == '__call__'  | 
					
						
							|  |  |  | 					&& typeof(obj) == 'function' ? | 
					
						
							|  |  |  | 				obj | 
					
						
							|  |  |  | 			// normal attr...
 | 
					
						
							|  |  |  | 			: obj[name] } | 
					
						
							| 
									
										
										
										
											2020-05-23 16:38:43 +03:00
										 |  |  | 	// wrap the callback if given...
 | 
					
						
							|  |  |  | 	var c = typeof(callback) == 'function' | 
					
						
							|  |  |  | 		&& function(obj){  | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			return callback(_get(obj, name), obj) } | 
					
						
							| 
									
										
										
										
											2020-05-23 16:38:43 +03:00
										 |  |  | 	return sources(...(c ? | 
					
						
							|  |  |  | 			[obj, name, c] | 
					
						
							| 
									
										
										
										
											2020-05-23 16:53:32 +03:00
										 |  |  | 			: [obj, name])) | 
					
						
							| 
									
										
										
										
											2020-05-23 16:38:43 +03:00
										 |  |  | 		.map(function(obj){  | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			return _get(obj, name) }) } | 
					
						
							| 
									
										
										
										
											2020-05-23 16:38:43 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | // Find the next parent attribute in the prototype chain.
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | // 	Get parent attribute value...
 | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | // 	parent(proto, name)
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // 		-> value
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | // 		-> undefined
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-30 01:17:13 +03:00
										 |  |  | // 	Get parent callable or .__call__ value (special-case)
 | 
					
						
							|  |  |  | // 	parent(proto, '__call__')
 | 
					
						
							|  |  |  | // 		-> value
 | 
					
						
							|  |  |  | // 		-> undefined
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | // 	Get parent method...
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // 	parent(method, this)
 | 
					
						
							| 
									
										
										
										
											2020-04-27 17:02:22 +03:00
										 |  |  | // 		-> meth
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | // 		-> undefined
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | // 	Get parent object...
 | 
					
						
							|  |  |  | // 	parent(this)
 | 
					
						
							|  |  |  | // 		-> parent
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // 
 | 
					
						
							|  |  |  | // The two forms differ in:
 | 
					
						
							|  |  |  | // 	- in parent(method, ..) a method's .name attr is used for name.
 | 
					
						
							|  |  |  | // 	- in parent(method, ..) the containing prototype is inferred.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: there are cases where method.name is not set (e.g. anonymous 
 | 
					
						
							|  |  |  | // 		function), so there a name should be passed explicitly...
 | 
					
						
							|  |  |  | // NOTE: when passing a method it is recommended to pass an explicit 
 | 
					
						
							|  |  |  | // 		reference to it relative to the constructor, i.e.:
 | 
					
						
							|  |  |  | // 			Constructor.prototype.method
 | 
					
						
							|  |  |  | // 		this will avoid relative resolution loops, for example: 
 | 
					
						
							|  |  |  | // 			this.method 
 | 
					
						
							|  |  |  | // 		deep in a chain will resolve to the first .method value visible 
 | 
					
						
							|  |  |  | // 		from 'this', i.e. the top most value and not the value visible
 | 
					
						
							|  |  |  | // 		from that particular level...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Example:
 | 
					
						
							|  |  |  | // 		var X = object.Constructor('X', {
 | 
					
						
							|  |  |  | //			__proto__: Y.prototype,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //			attr: 123,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 			method: function(){
 | 
					
						
							|  |  |  | // 				// get attribute...
 | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | // 				var a = object.parent(X.prototype, 'attr')
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 				// get method...
 | 
					
						
							| 
									
										
										
										
											2020-04-30 20:04:42 +03:00
										 |  |  | // 				var ret = object.parent(X.prototype.method, this)
 | 
					
						
							|  |  |  | // 					.call(this, ...arguments)
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 				// ...
 | 
					
						
							|  |  |  | // 			}
 | 
					
						
							|  |  |  | // 		})
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-30 16:41:19 +03:00
										 |  |  | // NOTE: in the general case this will get the value of the returned 
 | 
					
						
							|  |  |  | // 		property/attribute, the rest of the way passive to props.
 | 
					
						
							|  |  |  | // 		The method case will get the value of every method from 'this' 
 | 
					
						
							|  |  |  | // 		and to the method after the match.
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // NOTE: this is super(..) replacement, usable in any context without 
 | 
					
						
							|  |  |  | // 		restriction -- super(..) is restricted to class methods only...
 | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | var parent = | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | module.parent = | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | function(proto, name){ | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	// special case: get parent...
 | 
					
						
							|  |  |  | 	if(arguments.length == 1){ | 
					
						
							|  |  |  | 		return proto.__proto__ } | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 	// special case: get method...
 | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | 	if(typeof(name) != typeof('str')){ | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 		var that = name | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | 		name = proto.name | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 		// sanity check...
 | 
					
						
							|  |  |  | 		if(name == ''){ | 
					
						
							|  |  |  | 			throw new  Error('parent(..): need a method with non-empty .name') } | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | 		// get first matching source...
 | 
					
						
							|  |  |  | 		proto = sources(that, name,  | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 				function(obj){  | 
					
						
							|  |  |  | 					return obj[name] === proto | 
					
						
							|  |  |  | 						&& module.STOP }) | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | 			.pop() } | 
					
						
							|  |  |  | 	// get first source...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	var c = 0 | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | 	var res = sources(proto, name,  | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			function(obj){  | 
					
						
							|  |  |  | 				return c++ == 1  | 
					
						
							|  |  |  | 					&& module.STOP }) | 
					
						
							| 
									
										
										
										
											2020-04-30 02:01:00 +03:00
										 |  |  | 		.pop()  | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	return !res ? | 
					
						
							|  |  |  | 			undefined | 
					
						
							|  |  |  | 		:(!(name in res) && typeof(res) == 'function') ? | 
					
						
							|  |  |  | 			res | 
					
						
							|  |  |  | 		: res[name] } | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 16:41:19 +03:00
										 |  |  | // Find the next parent property descriptor in the prototype chain...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	parentProperty(proto, name)
 | 
					
						
							|  |  |  | // 		-> prop-descriptor
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This is like parent(..) but will get a property descriptor...
 | 
					
						
							|  |  |  | var parentProperty = | 
					
						
							|  |  |  | module.parentProperty = | 
					
						
							|  |  |  | function(proto, name){ | 
					
						
							|  |  |  | 	// get second source...
 | 
					
						
							|  |  |  | 	var c = 0 | 
					
						
							|  |  |  | 	var res = sources(proto, name,  | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 			function(obj){  | 
					
						
							|  |  |  | 				return c++ == 1  | 
					
						
							|  |  |  | 					&& module.STOP }) | 
					
						
							| 
									
										
										
										
											2020-04-30 16:41:19 +03:00
										 |  |  | 		.pop()  | 
					
						
							|  |  |  | 	return res ? | 
					
						
							|  |  |  | 		// get next value...
 | 
					
						
							|  |  |  | 		Object.getOwnPropertyDescriptor(res, name) | 
					
						
							|  |  |  | 		: undefined } | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:17:42 +03:00
										 |  |  | // Find the next parent method and call it...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-06 05:30:11 +03:00
										 |  |  | // 	parentCall(proto, name, this, ..)
 | 
					
						
							|  |  |  | // 	parentCall(meth, this, ..)
 | 
					
						
							| 
									
										
										
										
											2020-04-27 17:02:22 +03:00
										 |  |  | // 		-> res
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | // 		-> undefined
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:17:42 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | // This also gracefully handles the case when no higher level definition 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 02:20:29 +03:00
										 |  |  | // is found, i.e. the corresponding parent(..) call will return undefined
 | 
					
						
							|  |  |  | // or a non-callable.
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:31:42 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:17:42 +03:00
										 |  |  | // NOTE: this is just like parent(..) but will call the retrieved method,
 | 
					
						
							|  |  |  | // 		essentially this is a shorthand to:
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | // 			parent(proto, name).call(this, ...)
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:17:42 +03:00
										 |  |  | // 		or:
 | 
					
						
							|  |  |  | // 			parent(method, this).call(this, ...)
 | 
					
						
							|  |  |  | // NOTE: for more docs see parent(..)
 | 
					
						
							|  |  |  | var parentCall = | 
					
						
							|  |  |  | module.parentCall = | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | function(proto, name, that, ...args){ | 
					
						
							| 
									
										
										
										
											2020-04-30 02:10:01 +03:00
										 |  |  | 	var meth = parent(proto, name) | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | 	return typeof(meth) == 'function' ? | 
					
						
							| 
									
										
										
										
											2020-04-30 02:10:01 +03:00
										 |  |  | 		meth.call(...( typeof(name) == typeof('str') ? | 
					
						
							|  |  |  | 			[...arguments].slice(2) | 
					
						
							|  |  |  | 			: [...arguments].slice(1) )) | 
					
						
							| 
									
										
										
										
											2020-04-27 04:16:35 +03:00
										 |  |  | 		: undefined } | 
					
						
							| 
									
										
										
										
											2020-04-27 01:17:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2020-04-30 19:50:19 +03:00
										 |  |  | // Mixin utils...
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 01:13:09 +03:00
										 |  |  | // Mix a set of methods/props/attrs into an object...
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | // 
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | //	mixinFlat(base, object, ...)
 | 
					
						
							|  |  |  | //		-> base
 | 
					
						
							| 
									
										
										
										
											2020-04-12 01:13:09 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2019-07-06 00:34:54 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // NOTE: essentially this is just like Object.assign(..) but copies 
 | 
					
						
							|  |  |  | // 		properties directly rather than copying property values...
 | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | // NOTE: this will not transfer several the special variables not listed
 | 
					
						
							|  |  |  | // 		by Object.keys(..).
 | 
					
						
							|  |  |  | // 		This includes things like .__proto__
 | 
					
						
							| 
									
										
										
										
											2019-07-05 20:34:19 +03:00
										 |  |  | var mixinFlat =  | 
					
						
							|  |  |  | module.mixinFlat =  | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | function(base, ...objects){ | 
					
						
							| 
									
										
										
										
											2019-07-05 20:34:19 +03:00
										 |  |  | 	return objects | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 		.reduce(function(base, cur){ | 
					
						
							| 
									
										
										
										
											2019-07-05 20:34:19 +03:00
										 |  |  | 			Object.keys(cur) | 
					
						
							|  |  |  | 				.map(function(k){ | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 					Object.defineProperty(base, k, | 
					
						
							| 
									
										
										
										
											2019-07-05 20:34:19 +03:00
										 |  |  | 						Object.getOwnPropertyDescriptor(cur, k)) }) | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 			return base }, base) } | 
					
						
							| 
									
										
										
										
											2019-07-05 20:34:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-12 01:13:09 +03:00
										 |  |  | // Mix sets of methods/props/attrs into an object as prototypes...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | // 	mixin(base, object, ..)
 | 
					
						
							|  |  |  | // 		-> base
 | 
					
						
							| 
									
										
										
										
											2020-04-12 01:13:09 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will create a new object per set of methods given and 
 | 
					
						
							|  |  |  | // mixinFlat(..) the method set into this object leaving the 
 | 
					
						
							|  |  |  | // original objects intact.
 | 
					
						
							|  |  |  | // 
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | // 		base <-- object1_copy <-- .. <-- objectN_copy <- base.__proto__
 | 
					
						
							| 
									
										
										
										
											2020-04-12 01:13:09 +03:00
										 |  |  | // 				
 | 
					
						
							| 
									
										
										
										
											2020-05-06 05:30:11 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // NOTE: this will only mix in non-empty objects...
 | 
					
						
							| 
									
										
										
										
											2020-04-12 01:13:09 +03:00
										 |  |  | var mixin =  | 
					
						
							|  |  |  | module.mixin =  | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | function(base, ...objects){ | 
					
						
							|  |  |  | 	base.__proto__ = objects | 
					
						
							| 
									
										
										
										
											2020-04-12 01:13:09 +03:00
										 |  |  | 		.reduce(function(res, cur){ | 
					
						
							| 
									
										
										
										
											2020-05-06 05:30:11 +03:00
										 |  |  | 			return Object.keys(cur).length > 0 ? | 
					
						
							|  |  |  | 				module.mixinFlat(Object.create(res), cur)  | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 				: res }, base.__proto__)  | 
					
						
							|  |  |  | 	return base } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Get matching mixins...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:20:20 +03:00
										 |  |  | // 	mixins(base, object[, callback])
 | 
					
						
							|  |  |  | // 	mixins(base, list[, callback])
 | 
					
						
							|  |  |  | // 		-> list
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	callback(base, obj, parent)
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | //		-> STOP
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:20:20 +03:00
										 |  |  | //		-> undefined
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | // NOTE: if base matches directly callback(..) will get undefined as parent
 | 
					
						
							|  |  |  | // NOTE: this will also match base...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | // NOTE: for more docs on the callback(..) see sources(..)
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | var mixins = | 
					
						
							|  |  |  | module.mixins = | 
					
						
							|  |  |  | function(base, object, callback){ | 
					
						
							|  |  |  | 	object = object instanceof Array ? | 
					
						
							|  |  |  | 		object | 
					
						
							|  |  |  | 		: [object] | 
					
						
							|  |  |  | 	var res = [] | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 	var o | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 	var parent | 
					
						
							|  |  |  | 	while(base != null){ | 
					
						
							|  |  |  | 		// match each object...
 | 
					
						
							|  |  |  | 		for(var obj of object){ | 
					
						
							|  |  |  | 			if(match(base, obj)){ | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 				o = callback  | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 					&& callback(base, obj, parent) | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 				// manage results...
 | 
					
						
							|  |  |  | 				res.push( | 
					
						
							|  |  |  | 					(o === undefined || o === module.STOP) ?  | 
					
						
							|  |  |  | 						[base] | 
					
						
							|  |  |  | 						: o ) | 
					
						
							|  |  |  | 				if(o === module.STOP){ | 
					
						
							|  |  |  | 					return res.flat() }  | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 				// match found, no need to test further...
 | 
					
						
							|  |  |  | 				break } } | 
					
						
							|  |  |  | 		parent = base | 
					
						
							|  |  |  | 		base = base.__proto__ } | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 	return res.flat() } | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Check of base has mixin...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	hasMixin(base, mixin)
 | 
					
						
							|  |  |  | // 		-> bool
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | var hasMixin = | 
					
						
							|  |  |  | module.hasMixin = | 
					
						
							|  |  |  | function(base, object){ | 
					
						
							| 
									
										
										
										
											2020-05-24 00:37:52 +03:00
										 |  |  | 	return mixins(base, object, function(){ return module.STOP }).length > 0 } | 
					
						
							| 
									
										
										
										
											2020-05-06 05:30:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Mix-out sets of methods/props/attrs out of an object prototype chain...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-06 19:27:34 +03:00
										 |  |  | // 	Mix-out first occurrence of each matching object...
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | // 	mixout(base, object, ..)
 | 
					
						
							|  |  |  | // 	mixout(base, 'first', object, ..)
 | 
					
						
							|  |  |  | // 		-> base
 | 
					
						
							| 
									
										
										
										
											2020-05-06 19:27:34 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 	Mix-out all occurrences of each matching object...
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | // 	mixout(base, 'all', object, ..)
 | 
					
						
							|  |  |  | // 		-> base
 | 
					
						
							| 
									
										
										
										
											2020-05-06 05:30:11 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-06 19:27:34 +03:00
										 |  |  | // NOTE: this is the opposite to mixin(..)
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:07:21 +03:00
										 |  |  | // NOTE: this used mixins(..) / match(..) to find the relevant mixins, 
 | 
					
						
							|  |  |  | // 		see those for more info...
 | 
					
						
							| 
									
										
										
										
											2020-05-06 05:30:11 +03:00
										 |  |  | var mixout = | 
					
						
							|  |  |  | module.mixout = | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | function(base, ...objects){ | 
					
						
							| 
									
										
										
										
											2020-05-06 19:27:34 +03:00
										 |  |  | 	var all = objects[0] == 'all' ? | 
					
						
							|  |  |  | 			!!objects.shift() | 
					
						
							|  |  |  | 		: objects[0] == 'first' ? | 
					
						
							|  |  |  | 			!objects.shift() | 
					
						
							|  |  |  | 		: false | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 	var remove = [] | 
					
						
							|  |  |  | 	mixins(base, objects, function(match, obj, parent){ | 
					
						
							|  |  |  | 		parent && remove.push(parent) | 
					
						
							|  |  |  | 		// when removing the first occurrence, don't check for obj again...
 | 
					
						
							|  |  |  | 		all || objects.splice(objects.indexOf(obj), 1) }) | 
					
						
							|  |  |  | 	// NOTE: we are removing on a separate stage so as not to mess with
 | 
					
						
							|  |  |  | 	// 		mixins(..) iterating...
 | 
					
						
							|  |  |  | 	remove | 
					
						
							| 
									
										
										
										
											2020-05-08 16:32:54 +03:00
										 |  |  | 		// XXX not sure why this is needed, needs thought...
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:02:05 +03:00
										 |  |  | 		.reverse() | 
					
						
							|  |  |  | 		.forEach(function(p){ | 
					
						
							|  |  |  | 			p.__proto__ = p.__proto__.__proto__ }) | 
					
						
							|  |  |  | 	return base } | 
					
						
							| 
									
										
										
										
											2020-04-12 01:13:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:32:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 02:27:54 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2020-04-30 19:50:19 +03:00
										 |  |  | // Constructor...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Make an uninitialized instance object...
 | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | // 	RawInstance(context, constructor, ...)
 | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | // 		-> instance
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will:
 | 
					
						
							|  |  |  | // 	- construct an object
 | 
					
						
							|  |  |  | // 		- if .__new__(..) is defined
 | 
					
						
							|  |  |  | // 			-> call and use its return value
 | 
					
						
							|  |  |  | //		- if prototype is a function or if .__call__(..) is defined
 | 
					
						
							|  |  |  | //			-> use a wrapper function
 | 
					
						
							| 
									
										
										
										
											2020-05-17 22:57:25 +03:00
										 |  |  | //		- if construct.__proto__ has .__rawinstance__(..)
 | 
					
						
							|  |  |  | //			-> use it to create an instance
 | 
					
						
							| 
									
										
										
										
											2020-05-02 21:01:51 +03:00
										 |  |  | //		- if constructor.__proto__ is a constructor
 | 
					
						
							|  |  |  | //			-> use it to create an instance
 | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | //		- else
 | 
					
						
							|  |  |  | //			-> use {}
 | 
					
						
							|  |  |  | // 	- link the object into the prototype chain
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:49:38 +03:00
										 |  |  | // This will not call .__init__(..), hence the "uninitialized".
 | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-30 17:50:29 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:49:38 +03:00
										 |  |  | // NOTE: "context" is only used when passeding to .__new__(..) if defined, 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 21:13:28 +03:00
										 |  |  | // 		and is ignored otherwise...
 | 
					
						
							|  |  |  | // NOTE: as this is simply an extension to the base JavaScript protocol this
 | 
					
						
							|  |  |  | // 		can be used to construct any object...
 | 
					
						
							| 
									
										
										
										
											2020-04-26 20:05:30 +03:00
										 |  |  | // 		Example:
 | 
					
						
							|  |  |  | // 			// new is optional...
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | // 			var l = new RawInstance(null, Array, 'a', 'b', 'c')
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:07:21 +03:00
										 |  |  | // NOTE: the following are not the same in structure but functionally 
 | 
					
						
							|  |  |  | // 		are identical:
 | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | // 			var C = Constructor('C', function(){ .. })
 | 
					
						
							|  |  |  | // 		and
 | 
					
						
							|  |  |  | // 			var C2 = Constructor('C2', { __call__: function(){ .. } })
 | 
					
						
							|  |  |  | // 		the difference is in C.prototype vs. C2.prototype, the first 
 | 
					
						
							|  |  |  | // 		being a function while the second is an object with a call 
 | 
					
						
							|  |  |  | // 		method...
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | // NOTE: essentially this is an extended version of Reflect.construct(..)
 | 
					
						
							|  |  |  | var RawInstance =  | 
					
						
							|  |  |  | module.RawInstance = | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | function(context, constructor, ...args){ | 
					
						
							| 
									
										
										
										
											2020-04-26 20:05:30 +03:00
										 |  |  | 	var _mirror_doc = function(func, target){ | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 		Object.defineProperty(func, 'toString', { | 
					
						
							|  |  |  | 			value: function(...args){ | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 				var f = typeof(target.prototype) == 'function' ?  | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 					target.prototype | 
					
						
							|  |  |  | 					: target.prototype.__call__ | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | 				return typeof(f) == 'function' ? | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 						module.normalizeIndent(f.toString(...args)) | 
					
						
							|  |  |  | 					: undefined }, | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 			enumerable: false, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		return func } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var obj = | 
					
						
							|  |  |  | 		// prototype defines .__new__(..)...
 | 
					
						
							|  |  |  | 		constructor.prototype.__new__ instanceof Function ? | 
					
						
							|  |  |  | 			constructor.prototype.__new__(context, ...args) | 
					
						
							| 
									
										
										
										
											2020-05-02 19:55:05 +03:00
										 |  |  | 		// native constructor...
 | 
					
						
							|  |  |  | 		: /\[native code\]/.test(constructor.toString()) ? | 
					
						
							|  |  |  | 			Reflect.construct(constructor, args) | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 		// callable instance...
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:07:21 +03:00
										 |  |  | 		// NOTE: we need to isolate the callable from instances, thus we
 | 
					
						
							|  |  |  | 		// 		reference 'constructor' directly rather than using 
 | 
					
						
							|  |  |  | 		// 		'this.constructor'...
 | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | 		: (typeof(constructor.prototype) == 'function' | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 				|| constructor.prototype.__call__ instanceof Function) ? | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 			_mirror_doc( | 
					
						
							|  |  |  | 				function(){ | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 					return ( | 
					
						
							|  |  |  | 						// .prototype is a function...
 | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | 						typeof(constructor.prototype) == 'function' ? | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 							// NOTE: we are not using .call(..) here as it
 | 
					
						
							|  |  |  | 							// 		may not be accesible through the prototype
 | 
					
						
							|  |  |  | 							// 		chain, this can occur when creating a 
 | 
					
						
							|  |  |  | 							// 		callable instance from a non-callable 
 | 
					
						
							|  |  |  | 							// 		parent...
 | 
					
						
							|  |  |  | 							Reflect.apply( | 
					
						
							|  |  |  | 								constructor.prototype, obj, [this, ...arguments]) | 
					
						
							| 
									
										
										
										
											2020-05-30 01:17:13 +03:00
										 |  |  | 						// .__call__(..) or fail semi-gracefully...
 | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 						: constructor.prototype.__call__ | 
					
						
							|  |  |  | 							.call(obj, this, ...arguments)) }, | 
					
						
							|  |  |  | 				constructor) | 
					
						
							| 
									
										
										
										
											2020-05-16 17:49:20 +03:00
										 |  |  | 		// recursively call .__rawinstance__(..)
 | 
					
						
							|  |  |  | 		: constructor.__proto__.__rawinstance__ ? | 
					
						
							|  |  |  | 			constructor.__proto__.__rawinstance__(context, ...args) | 
					
						
							| 
									
										
										
										
											2020-05-03 03:19:37 +03:00
										 |  |  | 		// use parent's constructor...
 | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | 		: (typeof(constructor.__proto__) == 'function' | 
					
						
							| 
									
										
										
										
											2020-05-02 19:55:05 +03:00
										 |  |  | 				&& constructor.__proto__ !== (function(){}).__proto__) ? | 
					
						
							| 
									
										
										
										
											2020-05-16 17:49:20 +03:00
										 |  |  | 			Reflect.construct(constructor.__proto__, args, constructor) | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 		// default object base...
 | 
					
						
							| 
									
										
										
										
											2020-05-02 19:55:05 +03:00
										 |  |  | 		: Reflect.construct(Object, [], constructor) | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-02 19:55:05 +03:00
										 |  |  | 	// link to prototype chain, if not done already...
 | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | 	obj.__proto__ !== constructor.prototype | 
					
						
							|  |  |  | 		&& (obj.__proto__ = constructor.prototype) | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return obj } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 19:50:19 +03:00
										 |  |  | // Make an object constructor function...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 	Make a constructor with an object prototype...
 | 
					
						
							| 
									
										
										
										
											2020-04-27 17:02:22 +03:00
										 |  |  | // 		Constructor(name, proto)
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | // 			-> constructor
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | // 	Make a constructor with a prototype and a constructor prototype...
 | 
					
						
							|  |  |  | // 		Constructor(name, constructor-mixin, proto)
 | 
					
						
							|  |  |  | // 			-> constructor
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Make a constructor with prototype extending parent-constructor...
 | 
					
						
							|  |  |  | // 		Constructor(name, parent-constructor, proto)
 | 
					
						
							| 
									
										
										
										
											2020-05-06 02:37:08 +03:00
										 |  |  | // 		Constructor(name, parent-constructor, constructor-mixin, proto)
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | // 			-> constructor
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The resulting constructor can produce objects in one of these ways:
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 	Create instance...
 | 
					
						
							|  |  |  | // 		constructor(..)
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | // 		new constructor
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 		new constructor(..)
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | // 			-> instance
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | //	Create raw/uninitialized instance...
 | 
					
						
							|  |  |  | //		constructor.__rawinstance__(..)
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | //		RawInstance(null, constructor, ..)
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | //			-> raw-instance
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // All produced objects are instances of the constructor
 | 
					
						
							|  |  |  | // 		instance instanceof constructor
 | 
					
						
							|  |  |  | // 			-> true
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // Create and initialization protocol:
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:14:39 +03:00
										 |  |  | // 	1) raw instance is created:
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | // 		a) constructor.__rawinstance__(..) / RawInstance(..) called:
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 			- call .__new__(..) if defined and get return value as 
 | 
					
						
							|  |  |  | // 				instance, or
 | 
					
						
							|  |  |  | // 			- if .__call__(..) defined or prototype is a function, wrap 
 | 
					
						
							|  |  |  | // 				it and use the wrapper function as instance, or
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:14:39 +03:00
										 |  |  | // 			- create an empty object
 | 
					
						
							|  |  |  | // 		b) instance linked to prototype chain
 | 
					
						
							|  |  |  | // 			set .__proto__ to constructor.prototype
 | 
					
						
							|  |  |  | // 	2) instance is initialized: 
 | 
					
						
							|  |  |  | // 		call .__init__(..) if defined
 | 
					
						
							|  |  |  | // 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-06 03:50:55 +03:00
										 |  |  | // Special attributes:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Sets parent constructor
 | 
					
						
							|  |  |  | // 	.__extends__ = constructor
 | 
					
						
							|  |  |  | // 		NOTE: this can be set on either constructor-mixin or proto but 
 | 
					
						
							|  |  |  | // 			not on both...
 | 
					
						
							|  |  |  | // 		NOTE: if .__proto__ is not set in the proto, then it will be 
 | 
					
						
							|  |  |  | // 			set to .__extends__.prototype by default.
 | 
					
						
							|  |  |  | // 		NOTE: setting this and proto.__proto__ to can be used to link the
 | 
					
						
							|  |  |  | // 			constructor and instance object to different prototype chains
 | 
					
						
							|  |  |  | // 		NOTE: this attr is only used if explicitly defined, inherited 
 | 
					
						
							|  |  |  | // 			values are ignored.
 | 
					
						
							|  |  |  | // 		XXX this may get removed in future versions.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:14:39 +03:00
										 |  |  | // Special methods (constructor):
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //  Handle uninitialized instance construction
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:14:39 +03:00
										 |  |  | // 	.__rawinstance__(context, ...)
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 		-> instance
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | // 		NOTE: This is a shorthand to RawInstance(..) see it for 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 			details.
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:14:39 +03:00
										 |  |  | // 
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // Special methods (.prototype):
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 	Create new instance object...
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:14:39 +03:00
										 |  |  | // 	.__new__(context, ..)
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 		-> object
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Handle instance call...
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:14:39 +03:00
										 |  |  | // 	.__call__(context, ..)
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 		-> ..
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 	Initialize instance object...
 | 
					
						
							| 
									
										
										
										
											2020-04-27 18:14:39 +03:00
										 |  |  | // 	.__init__(..)
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 		-> ..
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | // NOTE: raw instance creation is defined by RawInstance(..) so see 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 02:42:31 +03:00
										 |  |  | // 		it for more info.
 | 
					
						
							|  |  |  | // NOTE: raw instance creation can be completely overloaded by defining
 | 
					
						
							| 
									
										
										
										
											2020-05-02 00:41:33 +03:00
										 |  |  | // 		.__rawinstance__(..) on the constructor.
 | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | // NOTE: if constructor-mixin's .__proto__ is set it will also be copied
 | 
					
						
							|  |  |  | // 		 to the created constructor...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Inheritance:
 | 
					
						
							|  |  |  | // 	A simple way to build C -> B -> A chain would be:
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2019-07-16 23:49:32 +03:00
										 |  |  | // 		// NOTE: new is optional...
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:31:42 +03:00
										 |  |  | // 		var A = new Constructor('A')
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-06 03:39:32 +03:00
										 |  |  | // 		var B = Constructor('B', A, {})
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:31:42 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | // 		var C = Constructor('C', B, {})
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | // 		var c = C()
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		c instanceof C		// -> true
 | 
					
						
							|  |  |  | // 		c instanceof B		// -> true
 | 
					
						
							|  |  |  | // 		c instanceof A		// -> true
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		A.prototype.x = 123
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		c.x 				// -> 123
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-04-27 01:31:42 +03:00
										 |  |  | // NOTE: this sets the proto's .constructor attribute, thus rendering it
 | 
					
						
							| 
									
										
										
										
											2020-04-30 20:04:42 +03:00
										 |  |  | // 		not reusable, to use the same prototype for multiple objects 
 | 
					
						
							|  |  |  | // 		clone it via. Object.create(..) or copy it...
 | 
					
						
							| 
									
										
										
										
											2020-04-27 16:54:44 +03:00
										 |  |  | // NOTE: to disable .__rawinstance__(..) handling set it to false in the 
 | 
					
						
							| 
									
										
										
										
											2020-05-02 00:41:33 +03:00
										 |  |  | // 		class prototype...
 | 
					
						
							| 
									
										
										
										
											2020-05-04 02:49:57 +03:00
										 |  |  | // NOTE: it is currently not possible to mix native unrelated types, for 
 | 
					
						
							|  |  |  | // 		example a callable array constructor will produce inconsistent 
 | 
					
						
							|  |  |  | // 		instance objects that in general will not work as expected...
 | 
					
						
							|  |  |  | // 			Reflect.construct(Array, [], Function)
 | 
					
						
							|  |  |  | // 		or
 | 
					
						
							|  |  |  | // 			Reflect.construct(Function, [], Array)
 | 
					
						
							|  |  |  | // 		will either initialize internal/hidden state for either one or 
 | 
					
						
							|  |  |  | // 		the other producing a semi-broken instance.
 | 
					
						
							|  |  |  | // 		It is however possible to mix related types as we are doing for 
 | 
					
						
							|  |  |  | // 		callable instances (Function + Object -- a function is an object).
 | 
					
						
							| 
									
										
										
										
											2020-05-06 02:37:08 +03:00
										 |  |  | // 		See README.md for more info.
 | 
					
						
							| 
									
										
										
										
											2020-05-25 00:53:56 +03:00
										 |  |  | // NOTE: making an object callable does not guarantee that it will pass
 | 
					
						
							|  |  |  | // 		the instanceof Function test, for that the prototype chain needs
 | 
					
						
							|  |  |  | // 		to be rooted in Function.
 | 
					
						
							|  |  |  | // 		though the typeof(..) == 'function' will always work.
 | 
					
						
							| 
									
										
										
										
											2020-05-30 01:21:02 +03:00
										 |  |  | // NOTE: this will fail with non-identifier names...
 | 
					
						
							|  |  |  | // 		XXX is this a bug or a feature??? =)
 | 
					
						
							| 
									
										
										
										
											2019-07-16 23:49:32 +03:00
										 |  |  | var Constructor =  | 
					
						
							|  |  |  | module.Constructor = | 
					
						
							|  |  |  | // shorthand...
 | 
					
						
							|  |  |  | module.C = | 
					
						
							| 
									
										
										
										
											2020-05-06 02:37:08 +03:00
										 |  |  | function Constructor(name, a, b, c){ | 
					
						
							|  |  |  | 	var args = [...arguments].slice(1, 4) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// parse args...
 | 
					
						
							|  |  |  | 	// 	Constructor(name[[, constructor[, mixin]], proto])
 | 
					
						
							|  |  |  | 	var proto = args.pop() || {} | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | 	var constructor_proto = typeof(args[0]) == 'function' ? | 
					
						
							| 
									
										
										
										
											2020-05-06 02:37:08 +03:00
										 |  |  | 		args.shift() | 
					
						
							|  |  |  | 		: undefined | 
					
						
							|  |  |  | 	var constructor_mixin = args.pop() | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// handle: 
 | 
					
						
							| 
									
										
										
										
											2020-05-06 02:37:08 +03:00
										 |  |  | 	// 	Constructor(name, constructor, ..)
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this is a bit too functional in style by an if-tree would 
 | 
					
						
							|  |  |  | 	// 		be more bulky and less readable...
 | 
					
						
							| 
									
										
										
										
											2020-05-06 03:39:32 +03:00
										 |  |  | 	constructor_proto | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 		// XXX need a better test -- need to test if .__proto__ was set 
 | 
					
						
							|  |  |  | 		// 		manually and not mess it up...
 | 
					
						
							|  |  |  | 		&& (proto.__proto__ === Object.prototype | 
					
						
							|  |  |  | 				|| proto.__proto__ === Function.prototype) | 
					
						
							|  |  |  | 			&& (proto.__proto__ = constructor_proto.prototype) | 
					
						
							|  |  |  | 			// restore func .toString(..) that was replaced to object's .toString(..) 
 | 
					
						
							|  |  |  | 			// in the previous op but only if it was not set by user...
 | 
					
						
							|  |  |  | 			&& (typeof(proto) == 'function' | 
					
						
							|  |  |  | 					&& proto.toString === Object.prototype.toString) | 
					
						
							|  |  |  | 				// XXX should we wrap this in normalizeIndent(..) ???
 | 
					
						
							|  |  |  | 				&& (proto.toString = Function.prototype.toString) | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-06 03:39:32 +03:00
										 |  |  | 	// handle: .__extends__
 | 
					
						
							|  |  |  | 	if(!constructor_proto){ | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | 		// handle .__extends__
 | 
					
						
							|  |  |  | 		a = Object.hasOwnProperty.call(proto, '__extends__') | 
					
						
							|  |  |  | 				&& proto.__extends__ | 
					
						
							|  |  |  | 		b = constructor_mixin != null | 
					
						
							|  |  |  | 				&& Object.hasOwnProperty.call(constructor_mixin, '__extends__') | 
					
						
							|  |  |  | 				&& constructor_mixin.__extends__ | 
					
						
							|  |  |  | 		// sanity check...
 | 
					
						
							|  |  |  | 		if(!!a && !!b){ | 
					
						
							|  |  |  | 			throw new Error('Constructor(..): ' | 
					
						
							|  |  |  | 				+'only one  of prototype.__extends__ or constructor.__extends__ ' | 
					
						
							|  |  |  | 				+'can exist.') } | 
					
						
							|  |  |  | 		constructor_proto = !!a ? a : b | 
					
						
							|  |  |  | 		// cleanup...
 | 
					
						
							|  |  |  | 		if(!!b){ | 
					
						
							|  |  |  | 			constructor_mixin = mixinFlat({}, constructor_mixin) | 
					
						
							|  |  |  | 			delete constructor_mixin.__extends__ } | 
					
						
							|  |  |  | 		!!constructor_proto | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			&& (proto.__proto__ = constructor_proto.prototype) } | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// the constructor base...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | 	var _constructor = function Constructor(){ | 
					
						
							| 
									
										
										
										
											2020-04-27 16:42:31 +03:00
										 |  |  | 		// create raw instance...
 | 
					
						
							|  |  |  | 		var obj = _constructor.__rawinstance__ ?  | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 			_constructor.__rawinstance__(this, ...arguments) | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | 			: RawInstance(this, _constructor, ...arguments) | 
					
						
							| 
									
										
										
										
											2020-04-27 16:42:31 +03:00
										 |  |  | 		// initialize...
 | 
					
						
							| 
									
										
										
										
											2019-07-16 23:49:32 +03:00
										 |  |  | 		obj.__init__ instanceof Function | 
					
						
							|  |  |  | 			&& obj.__init__(...arguments) | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 		return obj } | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 	_constructor.name = name | 
					
						
							|  |  |  | 	// just in case the browser refuses to change the name, we'll make
 | 
					
						
							|  |  |  | 	// it a different offer ;)
 | 
					
						
							| 
									
										
										
										
											2019-07-16 23:49:32 +03:00
										 |  |  | 	_constructor.name == 'Constructor' | 
					
						
							| 
									
										
										
										
											2020-04-26 19:30:49 +03:00
										 |  |  | 		// NOTE: this eval(..) should not be a risk as its inputs are
 | 
					
						
							|  |  |  | 		// 		static and never infuenced by external inputs...
 | 
					
						
							| 
									
										
										
										
											2020-05-30 01:21:02 +03:00
										 |  |  | 		// NOTE: this will fail with non-identifier names...
 | 
					
						
							| 
									
										
										
										
											2019-07-16 23:49:32 +03:00
										 |  |  | 		&& eval('_constructor = '+ _constructor | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | 				.toString() | 
					
						
							|  |  |  | 				.replace(/Constructor/g, name)) | 
					
						
							| 
									
										
										
										
											2020-04-26 19:59:56 +03:00
										 |  |  | 	// set .toString(..)...
 | 
					
						
							| 
									
										
										
										
											2018-08-20 16:01:37 +03:00
										 |  |  | 	// NOTE: do this only if .toString(..) is not defined by user...
 | 
					
						
							| 
									
										
										
										
											2020-05-02 20:51:10 +03:00
										 |  |  | 	// XXX revise this test...
 | 
					
						
							| 
									
										
										
										
											2020-05-24 23:59:01 +03:00
										 |  |  | 	;((constructor_mixin || {}).toString === Function.prototype.toString | 
					
						
							|  |  |  | 			|| (constructor_mixin || {}).toString === Object.prototype.toString) | 
					
						
							| 
									
										
										
										
											2019-07-16 23:49:32 +03:00
										 |  |  | 		&& Object.defineProperty(_constructor, 'toString', { | 
					
						
							| 
									
										
										
										
											2018-08-20 16:01:37 +03:00
										 |  |  | 			value: function(){  | 
					
						
							|  |  |  | 				var args = proto.__init__ ? | 
					
						
							|  |  |  | 					proto.__init__ | 
					
						
							|  |  |  | 						.toString() | 
					
						
							| 
									
										
										
										
											2020-04-30 20:04:42 +03:00
										 |  |  | 						.split(/\n/)[0] | 
					
						
							|  |  |  | 							.replace(/function\(([^)]*)\){.*/, '$1') | 
					
						
							| 
									
										
										
										
											2018-08-20 16:01:37 +03:00
										 |  |  | 					: '' | 
					
						
							|  |  |  | 				var code = proto.__init__ ? | 
					
						
							|  |  |  | 					proto.__init__ | 
					
						
							|  |  |  | 						.toString() | 
					
						
							|  |  |  | 						.replace(/[^{]*{/, '{') | 
					
						
							|  |  |  | 					: '{ .. }' | 
					
						
							| 
									
										
										
										
											2020-05-08 15:42:32 +03:00
										 |  |  | 				return `${this.name}(${args})${module.normalizeIndent(code)}` }, | 
					
						
							| 
									
										
										
										
											2018-08-20 16:01:37 +03:00
										 |  |  | 			enumerable: false, | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2020-05-02 21:01:51 +03:00
										 |  |  | 	// set generic raw instance constructor...
 | 
					
						
							| 
									
										
										
										
											2020-04-27 16:54:44 +03:00
										 |  |  | 	_constructor.__rawinstance__ instanceof Function | 
					
						
							| 
									
										
										
										
											2020-04-27 16:42:31 +03:00
										 |  |  | 		|| (_constructor.__rawinstance__ =  | 
					
						
							|  |  |  | 			function(context, ...args){ | 
					
						
							| 
									
										
										
										
											2020-05-08 18:36:51 +03:00
										 |  |  | 				return RawInstance(context, this, ...args) }) | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | 	!!constructor_proto | 
					
						
							|  |  |  | 		&& (_constructor.__proto__ = constructor_proto) | 
					
						
							|  |  |  | 	_constructor.prototype = proto | 
					
						
							| 
									
										
										
										
											2020-05-06 14:30:32 +03:00
										 |  |  | 	_constructor.prototype.constructor = _constructor | 
					
						
							| 
									
										
										
										
											2020-05-03 03:19:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-03 03:03:18 +03:00
										 |  |  | 	// NOTE: this is intentionally last, this enables the user to override
 | 
					
						
							|  |  |  | 	// 		any of the system methods...
 | 
					
						
							|  |  |  | 	// NOTE: place the non-overridable definitions after this...
 | 
					
						
							|  |  |  | 	!!constructor_mixin | 
					
						
							|  |  |  | 		&& mixinFlat( | 
					
						
							|  |  |  | 			_constructor, | 
					
						
							|  |  |  | 			constructor_mixin) | 
					
						
							| 
									
										
										
										
											2020-05-12 02:33:25 +03:00
										 |  |  | 		// also transfer non-default constructor_mixin.__proto__
 | 
					
						
							|  |  |  | 		&& constructor_mixin.__proto__ !== Object.prototype | 
					
						
							|  |  |  | 			&& (_constructor.__proto__ = constructor_mixin.__proto__) | 
					
						
							| 
									
										
										
										
											2020-05-02 21:01:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-29 21:15:46 +03:00
										 |  |  | 	return _constructor } | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-24 21:20:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-07 21:49:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-20 23:45:54 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |