62 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			62 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
Function.prototype.addRuntimeChecker = function() {
 | 
						|
	var handler = {
 | 
						|
		apply: function(target, thisArg, argumentValues) {
 | 
						|
			// https://stackoverflow.com/a/31194949
 | 
						|
			var argumentNames = target.toString()
 | 
						|
				.replace(/[/][/].*$/mg,'') // strip single-line comments
 | 
						|
				.replace(/\s+/g, '') // strip white space
 | 
						|
				.replace(/[/][*][^/\*]*[*][/]/g, '') // strip multi-line comments  
 | 
						|
				.split('){', 1)[0].replace(/^[^(]*[(]/, '') // extract the parameters  
 | 
						|
				.replace(/=[^,]+/g, '') // strip any ES6 defaults  
 | 
						|
				.split(',').filter(Boolean); // split & filter [""]
 | 
						|
 | 
						|
			var argumentNamesWithoutTypes = [];
 | 
						|
 | 
						|
			for (var i = 0; i < argumentValues.length; i++) {
 | 
						|
				// Get type from parameter name
 | 
						|
				var match = argumentNames[i].match(/(.+)_(\w+)/);
 | 
						|
				if (!match || match.length < 3) {
 | 
						|
					argumentNamesWithoutTypes.push(argumentNames[i]);
 | 
						|
					continue;
 | 
						|
				}
 | 
						|
 | 
						|
				argumentNamesWithoutTypes.push(match[1]);
 | 
						|
 | 
						|
				var type = match[2];
 | 
						|
 | 
						|
				// Check types
 | 
						|
				if (typeof argumentValues[i] !== type)
 | 
						|
					throw new Error("Invalid argument #" + i + " - Expected " + type + ", got " + typeof argumentValues[i]);
 | 
						|
			}
 | 
						|
 | 
						|
			// Assign actual names to window object before calling functions
 | 
						|
			var oldWindow = {};
 | 
						|
			for (var i = 0; i < argumentNamesWithoutTypes.length; i++) {
 | 
						|
				var name = argumentNamesWithoutTypes[i];
 | 
						|
 | 
						|
				oldWindow[name] = window[name];
 | 
						|
				window[name] = argumentValues[i];
 | 
						|
			}
 | 
						|
 | 
						|
			// Call function
 | 
						|
			var runtimeCheckerResult = target.apply(thisArg, argumentValues);
 | 
						|
 | 
						|
			// Re-assign old window values
 | 
						|
			for (var name in oldWindow) {
 | 
						|
				if (!oldWindow.hasOwnProperty(name)) continue;
 | 
						|
 | 
						|
				window[name] = oldWindow[name];
 | 
						|
			}
 | 
						|
 | 
						|
			return runtimeCheckerResult;
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	return new Proxy(this, handler);
 | 
						|
}
 | 
						|
 | 
						|
window.typedFunction = function(func) {
 | 
						|
	return func.addRuntimeChecker();
 | 
						|
}
 | 
						|
 |