Locating Javascript symbols in source

Locating a Javascript function

There are various ways of how to define/set/override a function in Javascript (usually through setting it as if it were a field on the class prototype object). Hence if you need to debug/modify/extend a function, it may not be easy to locate. You can use the following regular expressions to find definition of a function (if implemented in one of the common ways). Replace FUNCTIONNAME with the name of the function.

The regex itself, e.g. for use in NetBeans:

function\s+FUNCTIONNAME[^a-zA-Z0-9_]|[^a-zA-Z0-9_]FUNCTIONNAME\s*[:=]\s*function|\[\s*['"]FUNCTIONNAME['"]\s*\]\s*=\s*function

The same regex escaped for use in bash:

egrep -r "function\s+FUNCTIONNAME[^a-zA-Z0-9_]|[^a-zA-Z0-9_]FUNCTIONNAME\s*[:=]\s*function|\[\s*['\"]FUNCTIONNAME['\"]\s*\]\s*=\s*function" *

This is especially useful with Selenium which uses same name functions in various classes/components. There may be various versions of the same class/component, depending on how the code is executed - via Selenium IDE or via webdriver (but only Selenium Core and IDE is relevant to SeLite).

Locating classes in Selenium IDE

In Selenium IDE sources search for class definitions with regex:

className *= *classCreate *\(

Locating variables and object fields

Replace VARIABLENAME with the name of the variable. The regex itself, e.g. for use in NetBeans:

[^a-zA-Z0-9_]VARIABLENAME\s*[:=]|\[\s*['"]VARIABLENAME['"]\s*\]\s*=|\.VARIABLENAME\s*[=]|var +([^\n;]+ *, *)*VARIABLENAME[ ,;\n]

Object fields from top-level variables

When searching for an object field (rather than a variable), if the above doesn’t find it as a field but only as a top-level variable, that may be when the Javascript file that defines the variable is loaded within a scope that is stored in the target object.

For example, chrome/content/selenium-runner.js defines a top-level variable var LOG. That file is loaded within scope of runner object from file content/debugger.js. That defines field LOG in runner object.

Search for (literal) .loadSubScript and find one that is .loadSubScript( locationOfJavascriptFileThatDefinesTheVariable, objectWhereThatVariableBecomesAField ).

Function intercepts

This is for extending or completely replacing behaviour of existing functions that come from Selenium or third party. It can be done for ordinary (non-member) functions (including class constructors) and also for methods (member functions of objects). Methods can be intercepted on either

Head/tail intercepts

Extending (rather than replacing) is useful for small changes, and it’s more likely to stay compatible with future updates from Selenium or third party. The original function is stored. The new function adds steps before and/or after calling the original function (with the same or different parameters). This approach is called head or tail intercept. If it’s supposed to return a value, it can return the result of the original function, or something different.

Head intercept with a modification of the parameter passed to the original function:

"use strict";
// The original function (it would come from Selenium or third party)
function greeting( name ) {return "Hello " +name;}

// Anonymous closure to keep 'originalGreeting' variable local
( function() {
    var originalGreeting= greeting;

    greeting= function greeting( name ) {
        if( !name ) {
            name= "guest";
        }
        return originalGreeting.call( null/*'this' object*/, name );
    };
  }
) ();

Tail intercept:

"use strict";
// The original function (it would come from Selenium or third party)
function greeting() {return "Hello";}

// Anonymous closure to keep 'originalGreeting' variable local
( function() {
    var originalGreeting= greeting;

    greeting= function greeting() {
        var originalResult= originalGreeting.call();
        return originalResult+ ", my friend.";
    };
} ) ();

If you use SeLite Bootstrap, see also Bootstrap > Intercepts.

Using synchronous DB API

Mozilla offers both synchronous and asynchronous API for accessing SQLite. I may have misunderstood their documentation and examples of using asynchronous calls, but it seems highly impractical to me: the only way to have a sequence of operations seemed to chain handler functions (one per each operation). Since the handlers are called from a separate thread (or after the main execution loop cycle?), there was no easy way to have the main thread wait for the result(s). And since cross-thread synchronisation is not defined in Javascript, it was all strange.

Also, synchronous API itself is a bit easier to use