Javascript Execution

Overview

You can implement Content Recognizers, Triggers, and Answer Generators in Javascript, namely the ECMAScript 6 version. This page describes the Javascript execution environment available and its constraints.

Although there are some limitations (described below), Javascript-backed plugins can be very powerful because you can use a real programming language to specify the desired behavior.

Language version and runtime environment

You can write scripts and EJS templates to implement Solve for All plugins, using either ECMAScript 6 or ECMAScript 5 syntax. In particular,

  • Scripts should be written in ES6 strict mode. Scripts may also optionally be written in TypeScript (not extensively tested yet), which is always strict.
  • EJS templates should be written in ES6 non-strict mode

To execute Javascript, Solve for All uses Rhino 1.7.7. In particular, the JSON object and the XML class of E4X (but not XML literals) are available in the environment. In your uploaded scripts and templates, you can use almost all ES6 features without worrying about language support in Rhino, since uploaded scripts and templates are always converted to plain ES5 first.

The following ES6 features are partially supported, or unsupported:

  • In ES6, many methods and properties were added to built-in classes and additional built-ins were added, but these aren't all available in Rhino. For now, it's best to use Underscore to get most of this functionality.
  • Unicode-aware regexes are not supported

Also, code that you eval() needs to conform to Rhino's natively supported syntax, which is version 1.8. You can use some, but not all, ES6 features like const and let declarations and some destructuring operations.

Built-in Libraries

All scripts have access to the following libraries:

Name Version Notes
Underscore.js 1.8.3 Available as the _ function
Underscore Inflection 1.4.0 Pre-mixed into the _ function
Underscore String 2.3.3 Pre-mixed into the _ function

Importable Libraries

Less commonly used libraries can be imported via CommonJS require() calls, like this:

const moment = require('moment');

just like in Node.js.

Currently the available libraries are:

Module Name Project Name Version
crypto-js crypto-js 3.1.5
ejs EJS 1.0.0
math Math.js 1.4.0
moment Moment.js 2.10.6
numeral Numeral.js 1.5.3
oauth-1.0a oauth-1.0a 1.0.0
spark-md5 SparkMD5 1.0.0
URI URI.js (includes Second Level Domain support) 1.14.1

To request a library be added to either the built-ins or the importable libraries, fork the example plugins project, and add your library to test_harness/builtins or test_harness/modules (for importable libraries). Note that we prefer that libraries be importable to reduce the startup time of the Javascript execution engine. Then submit a pull request, with an explanation of why you need the library, and we will add it as long as it makes sense.

Other APIs

Answer Generators implemented in Javascript also have access to the Web Request API and the Console API.

Aliases

For convenience, all of the functions and constants in the Math object are defined in the global namespace. For example, max is an alias for Math.max. So you can write max(x, y) instead of Math.max(x, y).

These special aliases are also defined:

  • pi: Alias for Math.PI
  • e: Alias for Math.E
  • ln: Alias for Math.log

Limitations

For security and service availability reasons, Solve for All limits the Javascript execution environment in the following ways:

  • Access to Java classes (normally present in a Rhino environment) is disabled.
  • Scripts are run in interpretative mode. This means scripts are run much slower than if run by an optimized Javascript engine.
  • Scripts are given a finite amount of memory and a limited time to run before they are killed.

Don't use your script to perform non-answer engine related functionality, like attacking the system, stealing user data, or mining Bitcoin. If we detect abuse, we may disable your account or take other preventative measures. For more details, see the Terms of Service.

Failure Behavior

If a script does not execute properly or is killed before it can finish, the behavior will be as follows:

Plugin Type Behavior if Script Fails
Content Recognizer Nothing is recognized by the failed Content Recognizer; no recognition keys are added to the answer results.
Trigger The failed Trigger does not activate.
Answer Generator No answer results are produced.

Development Tips

If you're writing an Answer Generator, take advantage of the Console API to see log messages.

For development or debugging of your scripts, you can enter an answer query containing Javascript and see the result of evaluating your code. For example, the query ?js _('_solve_for_all').camelize() uses Underscore String to convert a string into camel case (try it). Note that this code is passed to eval() so the syntax must be directly understood by Rhino 1.7.7.