Fork me on GitHub

Aether - Purify Your Users' JavaScript


Aether aims to make it easy for people to learn and write JavaScript and CoffeeScript by helping them catch and fix bugs, letting them see and more easily understand the execution of their program (like Bret Victor commanded!), and giving them tips on how they can improve their code. CodeCombat is behind it.


Get in touch

You can use the GitHub issues, the Discourse forum, the Google Group, the HipChat, or email Nick.

What is it?

It's a JavaScript library (written in CoffeeScript) that takes user code as input; does computer-sciencey transpilation things to it with the help of JSHint, Esprima, JS_WALA, escodegen, and traceur; and gives you:

  1. incomplete Linting with totally configurable error/warning/info messages. Instead of "Warning: Line 2: Missing semicolon.", you could make Aether say, "Error: Put a semicolon here on line 2 after 'this.explode()' to end the statement.", or "fyi: might want a ; here amiga", or nothing at all. Aether does spellchecking based on what properties should exist, too: Should be 'destroy', not 'destory'.

  2. Transformation like with node-falafel, but even easier, because your source transformation plugins can run either before or after the AST is normalized with JS_WALA.

  3. incomplete Sandboxing so that you can actually run user code in the browser without worrying if the world will end. Well, not actually. That is hard; one should at least use a web worker. But good enough to foil most hacking attempts.

  4. Instrumentation so that when the code is run, you'll know everything that happened. Count statements executed, step through the flow of execution, retrieve past variable states, and even pause and resume execution whenever you want. Pause after every statement? Sure!

  5. incomplete Time-travel debugging to combine and surpass the best parts of both stepping debugging and logging.

  6. planned Style analysis: metrics on things like what kind of indentation and bracket style the code uses, whether it uses recursion or regular expressions, etc.

  7. planned Autocompletion suggestions based on unfinished code.

  8. planned Other goodies! You can let your users code in ES6 now and hopefully CoffeeScript soon.

Development Status

Alpha–watch out! CodeCombat is using it right now, but there are many bugs and missing pieces. If you'd be interested in Aether were it solid and finished, please tell us so we can get an idea of where else it might be useful and how it should work.

How does it work?

Aether uses JSHint, Esprima, Acorn, JS_WALA, escodegen, and traceur together to carry out this process:

  1. We use JSHint to provide lint warnings and errors.
  2. We wrap the user code in a function declaration, since Aether expects the user code to be the body of a function.
  3. We do a regexp replace step to check for common mistakes. This will probably go away.
  4. We parse it with Esprima to get an AST. If it's invalid, we fall back to parsing with Acorn in loose mode so that we can get a workable AST despite the errors.
  5. We run a bunch of pre-normalization transformations on the AST to grab variable declarations, original statement ranges, and check for several more types of mistakes.
  6. We use JS_WALA to normalize the AST so that there'll be far fewer cases to handle in the next transformation step.
  7. We output that transformed AST to JS again using escodegen, since our transformations need to operate on an AST with matching original source at the same time.
  8. We parse again with Esprima and run a bunch of post-normalization transformations on that AST to do things like inserting instrumentation, protecting external objects, and adding yield statements.
  9. We use traceur to convert our ES6 yield statements to giant ES5 state machines to simulate generators, if we added any yields.
  10. We add one more function to intercept references to this for security.

License

The MIT License (MIT)

If you'd like to contribute, please sign the CodeCombat contributor license agreement so we can accept your pull requests. It is easy.

Load example:

Write some JavaScript here.

Use Aether on it.

Problems detected show up here.

Gory transpiled code!

Execution metrics!

Console output lurks here.


            

Flow analysis!

Aether runs in node and the browser using node-style CommonJS requires.

In the browser, grab build/aether.js or build/aether.min.js. Or in node, runnpm install aether --save, which should add an entry like "aether": "~0.1.0" to your dependencies in package.json. Then, in your code:

var Aether = require('aether');
var aether = new Aether();
aether.lint(someGnarlyUserCode);
aether.problems.warnings;
[{range: [{ofs: 15, row: 2, col: 0}, {ofs: 22, row: 2, col: 7}],
  id: 'aether_MissingThis',
  message: 'Missing `this.` keyword; should be `this.getEnemies`.',
  hint: 'There is no function `getEnemys`, but `this` has a method `getEnemies`.',
  level: "warning"}]
aether.transpile(someGnarlyUserCode);
var gnarlyFunc = aether.createFunction();
gnarlyFunc();
// At any point, you can check aether.problems, aether.style, aether.flow, aether.metrics, etc.
// See more examples in the tests: https://github.com/codecombat/aether/tree/master/test

In the browser, it currently depends on lodash (not underscore). We test in Chrome and node, and it will probably work in other modern browsers.

Want to hack on Aether? Awesome!

Setting Up Your Environment

The GitHub Repository has everything you need to work on Aether. You'll need Node, NPM and Git installed.

  1. Clone the repository:
    git clone https://github.com/codecombat/aether.git
  2. Go to the directory and npm install:
    cd aether
    npm install

Running The Environment

From the aether directory, run:

grunt  # or grunt watch, to recompile on any changes

Then you can navigate to file://localhost/some/path/to/aether/build/index.html and see it in action.

Things to keep in mind

  • Edit the CoffeeScript source in /src and /test, not the transpiled JavaScript in aether/lib.
  • Remember to create tests in the /test folder.

What to work on?

TODO

You could always also add more tests or handle reported issues.