Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

structured.js is a Javascript library that provides a simple interface for verifying the structure of Javascript code, backed by the abstract syntax tree generated by Esprima. It is particularly useful in checking beginner code to provide feedback as part of Khan Academy's CS curriculum.

Structured.js works in-browser <script src='structured.js'></script>, or as a standalone npm module.

A structure is any valid Javascript code which contains blanks ( _ characters) and stand-ins ($str) to match values. The structure is sensitive to nesting and ordering. The matcher only requires that code contain the structure -- extra code has no effect.


Try structured.js yourself to see it in action.

Also check out the pretty display demo for more user-friendly structures.


var structure = function() {
  if (_) {
    _ += _;
    for (var $a = _; $a < $b; $a += _) {
        _($a, $b, 30, 30);

var code = "/* some code */";

var result = Structured.match(code, structure);

Returns true for the code:

if (y > 30 && x > 13) {
   x += y;
   for (var i = 0; i < 100; i += 1) {
     rect(i, 100, 30, 30);

Check out the demo for more, or look at the tests.

Advanced -- Variable Callbacks

To allow tighter control over what exactly is allowed to match your $variable, you may provide a mapping from variable names to function callbacks. These callbacks can enable NOT, OR, and AND functionality on the wildcard variables, for example.

Callback parameters should be the same as the name of the wildcard variables they are matching. The callback takes in a proposed value for the variable and accepts/rejects it by returning a boolean. The callback may instead return an object such as {failure: "failure message"} as well if you'd like to explain exactly why this value is not allowed.

For instance, say we want to check the value we assign to a var -- check that it is really big, and that it is bigger than whatever we increment it by. It would look like this:

var structure = function() {var _ = $num; $num += $incr; };
var code = "var foo = 400; foo += 3;";
var varCallbacks = [
  function($num) {
    return num.value > 100;  // Just return true/false
  function($num, $incr) {
    if (num.value <= incr.value) {
      // Return the failure message
      return {failure: "The increment must be smaller than the number."};
    return true;
var match = Structured.match(code, structure, {varCallbacks: varCallbacks});
if (!match) {
  // varCallbacks.failure contains the error message, if any.
  console.log("The problem is: " + varCallbacks.failure);

Note that the callbacks receive objects that contain a subtree of the Esprima parse tree, not a raw value. Also note that the callbacks run statically, not dynamically -- so, you will only be able to directly check literal values (i.e., 48), not computed values (24*2, myVar, etc). The callbacks also ignore any variable callbacks for variables that do not actually appear in the structure you've passed in.

Go to the demo to try it out.


Run structured.js tests with npm test or by opening browser-test/index.html.


Esprima and UnderscoreJS for the framework, QUnit for the test suite, RainbowJS for prettified structures.