(info) This AI is still in early stages of development.

Hook API

Make functions "hookable" so you can pre-process their input and post-process their output...

 

Overview

The Hook API lets you turn an existing function in to a hookable function:

Make a function hookable
var myFn = function foo(a, b) {
	return a + b;
}
 
myFn.canHook; // false
 
var myHookedFn = Hook(myFn);
 
myFn.canHook; // false
myHookedFn.canHook; // myFn (typecasts to true)
 
myHookedFn.canHook.name; // "foo"
myHookedFn.canHook.length; // 2 (myFn defines 2 formal parameters)
 
myHookedFn.name; // "hooked"
myHookedFn.length; // 0 (doesn't define formal parameters)

It's a bit like function.wraps(), in that the original function (eg. myFn) will be wrapped in a new function (eg. myHookedFn). The main difference is that once you've made a function hookable, you can add input and output hooks to it.

Input hooks

An input hook lets you alter the parameters (params) that will be sent to the inner function. The input parameters are:

  • params – an editable array of parameters that will be sent to the inner function
  • args – a read-only array of parameters that were used on the outer function
  • hooked – a reference to the outer function (get the inner function via hooked.canHook)

Continuing from the last example...

Create an input hook to change params
myHookedFn.onInput; // 0 (typecasts to false)
 
// catch the fish
myHookedFn.onInput = function(params, args, hooked) {
	// play with it (note: arguments is immutable)
	params[0] = 10; // a => 10
	// throw it back in the river
	return params;
}
 
myHookedFn.onInput; // 1 (typecasts to true)
 
myFn(1, 2); // 3 (1 + 2)
myHookedFn(1, 2); // returns 12 (10 + 2)

Remember to return the params array, otherwise the inner function won't be called.

Output hooks

An output hook lets you alter the functions return value. 

The parameters are:

  • result – the editable result returned by the inner function
  • params – a read-only array of parameters that will be sent to the inner function
  • args – a read-only array of parameters that were used on the outer function
  • hooked – a reference to the outer function (get the inner function via hooked.canHook)

Continuing from the last example...

Create an output hook to change results
myHookedFn.onOutput; // 0
 
myHookedFn.onOutput = function(result, params, args, hooked) {
	result -= 3;
	return result;
}
 
myHookedFn.onOutput; // 1
 
myHookedFn(1, 2); // 9 ((10 + 2) - 3)

Remember to return the result, otherwise the return value sent to the calling script will be undefined.

Multiple hooks

You can add any number of input/output hooks:

  • All the input hooks will run first, on a first-come first-served basis
  • The inner function will then be invoked (unless one of the input hooks aborted the invocation)
  • All the output hooks will run last, on a first-come first-served basis
  • The final result will be passed back to the calling script

Continuing from the last example...

Add as many hooks as you want
// add another output function, it will be invoked after previous one
myHookedFn.onOutput = function(result, params, args, hooked) {
	// params[0] == 10 due to input hook
	result += args[0]; // args[0] unaffected by alterations to params array
	return result;
}
 
myHookedFn.onOutput; // 2
 
myHookedFn(1, 2); // 10 (((10 + 2) - 3) + 1)
 
myHookedFn(-4, 5); // 8 (((10 + 5) - 3) + -4)

Aborting function invocations

You can abort a function run during an input hook by returning undefined instead of the params array.

Continuing from the last example...

Terminate function invocations
myHookedFn.onInput = function(params, args, hooked) {
	if (args[0] < 0) {
		return void Hook; // kill the function invocation
		// note: output hooks will be skipped
	}
}
 
myHookedFn(1, 2); // 10 (((10 + 2) - 3) + 1)
 
myHookedFn(-4, 5); // undefined (invocation was aborted)

Notes

Hook(Hook); // Error

Hook(myHookedFn) === myHookedFn

Define("foo", myFn); Hook(myFn); // Error

Define("foo", Hook(myFn)); // ±1

Availability STABLE

Requires: