Labs/Jetpack/JEP/28
Abstract
The Cuddlefish Minilib builds on JEP 25 - Boosters to provide a basic infrastructure for developing traditional XULRunner Extensions. It will also be the basis for Jetpack, as Jetpack itself is a XULRunner Extension.
Motivation and Rationale
In many ways, this JEP is a refactored formalization of Jetpack's current implementation that will allow many of Jetpack's core benefits to be leveraged by any XULRunner Extension. Another way of putting this is that Cuddlefish nicely decouples functionality that is specific to Jetpack from functionality that many other extensions—Labs extensions in particular—would like to have, and which they often end up re-implementing from scratch to some extent.
Additionally, by moving to a SecurableModule-based architecture, Jetpack's runtime can easily be decoupled from the about:jetpack page, which will resolve a number of deficiencies (such as the inability to look at the API documentation and use the built-in code editor simultaneously).
Requirements and Scope
To address issues present in traditional Extension development, Cuddlefish provides the following:
- A simple, straightforward mechanism for writing and executing test cases, inspired by Python's nose package.
- A mechanism for tracking JS objects of interest to aid in memory profiling and leak detection.
- A mechanism for registering callbacks that perform cleanup tasks when modules are unloaded.
- A mechanism for easily reporting errors with full stack tracebacks.
- A simple mechanism for dropping-in optional third-party packages or SecurableModules.
Cuddlefish should also have the following characteristics:
- Beautiful, concise documentation.
- A rigorous test suite ensuring that Cuddlefish doesn't break as the Mozilla platform evolves.
- Solid developer ergonomics ensuring that developers can easily find out why something they're doing isn't working.
As is implied by the word "minilib", Cuddlefish is intended to be very small and only contain the bare minimum of functionality that all extensions need. This means, for instance, that a module that wraps clipboard access, or a module that computes SHA1 hashes, will not be included in Cuddlefish—though such modules may certainly be bundled with an extension and easily loaded using Cuddlefish.
The following are outside the scope of Cuddlefish:
- Cuddlefish doesn't "touch" the command line at all; it's just a drop-in library to include in existing XULRunner Extensions or applications. As such, the following are out of scope:
- A tool for creating new XULRunner Extension or application directory structures "from scratch".
- A build system for creating XPIs or XULRunner applications.
- A documentation system.
- A package management system.
- A user interface. Cuddlefish doesn't make any assumptions about whether you're using XUL, HTML, stdout, or something else. The exception to this is the logging console, which obviously needs something to output to, but multiple implementations will be built-in to the minilib, with the option for clients to provide their own.
Usage
Cuddlefish consists of a single directory that can be dropped-into an extension's directory structure and loaded either through a <script> tag in a chrome-privileged document or a JS module.
For example, assuming that the Cuddlefish directory is placed in the extension's chrome/content/lib directory, a file at chrome/content/main.html can load it like so:
<html>
<script src="lib/cuddle.js"></script>
<script>
var loader = new Cuddlefish.Loader({rootPath: "lib/"});
loader.runScript("console.log('hello');");
</script>
</html>
Globals
Every script and module loaded by Cuddlefish comes with a handful of globals to make life easier for developers.
In addition to the globals provided by the SecurableModule standard and the Mozilla platform, each module has the following global variables that reflect idioms present in most Mozilla platform/extension code:
- Cc is mapped to Components.classes.
- Ci is mapped to Components.interfaces.
- Cu is mapped to Components.utils.
- Cr is mapped to Components.results.
In addition to these, the following globals are available to all modules.
console
console is an object with methods similar to Firebug's console object:
console.log(object[, object, ...])
Logs an informational message to the console. Depending on console's underlying implementation and user interface, you may be able to introspect into the properties of non-primitive objects that are logged.
console.info(object[, object, ...])
A synonym for console.log().
console.warn(object[, object, ...])
Logs a warning message to the console.
console.error(object[, object, ...])
Logs an error message to the console.
console.debug(object[, object, ...])
Logs a debug message to the console.
console.trace()
Inserts a stack trace into the console at the point this function is called.
memory
memory is an object that exposes functionality to track objects of interest and help prevent memory leaks.
memory.track(object, [name])
Marks object for being tracked, and categorizes it with the given name. If name isn't specified, the memory tracker attempts to infer the name by first checking the object's constructor.name; if that fails or results in the generic Object, the stack is inspected and the name of the current function being executed—which is assumed to be a constructor function—is used.
memory.get([name])
Returns an Array of all live tracked objects that have been categorized with the given name. If name isn't provided, all live tracked objects are returned.
Modules
The following modules come built-in with Cuddlefish and can be retrieved with a call to require().
url
The url module provides functionality for the parsing and retrieving of URLs.
url.resolve(base, relative)
Returns an absolute URL given a base URL and a relative URL.
traceback
The traceback module contains functionality similar to Python's traceback module.
JSON Traceback Objects
Tracebacks are stored in JSON format. The stack is represented as an array in which the most recent stack frame is the last element; each element thus represents a stack frame and has the following keys:
| filename | The name of the file that the stack frame takes place in. |
| lineNo | The line number is being executed at the stack frame. |
| funcName | The name of the function being executed at the stack frame, or null if the function is anonymous or the stack frame is being executed in a top-level script or module. |
Functions
traceback.fromException(exception)
Attempts to extract the traceback from exception, returning the JSON representation of the traceback or null if no traceback could be extracted.
traceback.get()
Returns the JSON representation of the stack at the point that this function is called.
traceback.format([tbOrException])
Given a JSON representation of the stack or an exception instance, returns a formatted plain text representation of it, similar to Python's formatted stack tracebacks. If no argument is provided, the stack at the point this function is called is used.
unload
The unload module allows modules to register callbacks that are called when Cuddlefish is unloaded. It is similar to the SecurableModule of the same name in the Narwhal platform.
Reference Implementation
An in-progress reference implementation for Cuddlefish can be found at:
http://hg.mozilla.org/users/avarma_mozilla.com/jep-28/
Just check out the Mercurial repository and read the README.