# falafel

Transform the [ast](http://en.wikipedia.org/wiki/Abstract_syntax_tree) on a
recursive walk.

[![browser support](http://ci.testling.com/substack/node-falafel.png)](http://ci.testling.com/substack/node-falafel)

[![build status](https://secure.travis-ci.org/substack/node-falafel.png)](http://travis-ci.org/substack/node-falafel)

This module is like [burrito](https://github.com/substack/node-burrito),
except that it uses [esprima](http://esprima.org) instead of
[uglify](https://github.com/mishoo/UglifyJS)
for friendlier-looking ast nodes.

![falafel döner](http://substack.net/images/falafel.png)

# example

## array.js

Put a function wrapper around all array literals.

``` js
var falafel = require('falafel');

var src = '(' + function () {
    var xs = [ 1, 2, [ 3, 4 ] ];
    var ys = [ 5, 6 ];
    console.dir([ xs, ys ]);
} + ')()';

var output = falafel(src, function (node) {
    if (node.type === 'ArrayExpression') {
        node.update('fn(' + node.source() + ')');
    }
});
console.log(output);
```

output:

```
(function () {
    var xs = fn([ 1, 2, fn([ 3, 4 ]) ]);
    var ys = fn([ 5, 6 ]);
    console.dir(fn([ xs, ys ]));
})()
```

## custom keyword

Creating custom keywords is super simple!

This example creates a new `beep` keyword that uppercases its arguments:

``` js
var falafel = require('falafel');
var src = 'console.log(beep "boop", "BOOP");';

function isKeyword (id) {
    if (id === 'beep') return true;
}

var output = falafel(src, { isKeyword: isKeyword }, function (node) {
    if (node.type === 'UnaryExpression'
    && node.keyword === 'beep') {
        node.update(
            'String(' + node.argument.source() + ').toUpperCase()'
        );
    }
});
console.log(output);
```

Now the source string `console.log(beep "boop", "BOOP");` is converted to:

```
$ node example/keyword.js
console.log(String("boop").toUpperCase(), "BOOP");
```

which we can execute:

```
$ node example/keyword.js | node
BOOP BOOP
```

Neat!

# methods

``` js
var falafel = require('falafel')
```

## falafel(src, opts={}, fn)

Transform the string source `src` with the function `fn`, returning a
string-like transformed output object.

For every node in the ast, `fn(node)` fires. The recursive walk is a
pre-traversal, so children get called before their parents.

Performing a pre-traversal makes it easier to write nested transforms since
transforming parents often requires transforming all its children first.

The return value is string-like (it defines `.toString()` and `.inspect()`) so
that you can call `node.update()` asynchronously after the function has
returned and still capture the output.

Instead of passing a `src` you can also use `opts.source`.

All of the `opts` will be passed directly to esprima except for `'range'` which
is always turned on because falafel needs it.

Some of the options you might want from esprima includes:
`'loc'`, `'raw'`, `'comments'`, `'tokens'`, and `'tolerant'`.

falafel uses a custom patch of esprima with support for an `opts.isKeyword()`
function. When `opts.isKeyword(id)` returns `true`, the string `id` will be
treated as a keyword. You can use this behavior to create custom unary
expression keywords.

An `opts.isKeyword(id)` value that is a string will be mapped to existing types.
The only currently supported string value is `"block"`.

# nodes

Aside from the regular [esprima](http://esprima.org) data, you can also call
some inserted methods on nodes.

Aside from updating the current node, you can also reach into sub-nodes to call
update functions on children from parent nodes.

## node.source()

Return the source for the given node, including any modifications made to
children nodes.

## node.update(s)

Transform the source for the present node to the string `s`.

Note that in `'ForStatement'` node types, there is an existing subnode called
`update`. For those nodes all the properties are copied over onto the
`node.update()` function.

## node.parent

Reference to the parent element or `null` at the root element.

# install

With [npm](http://npmjs.org) do:

```
npm install falafel
```

# license

MIT

