This AI is still in early stages of development.
Hook API
- Aubergine
Overview
The Hook API lets you turn an existing function in to a hookable function:
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...
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...
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 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...
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