# ast-util

Utilities for AST transformers.

## Install

```
$ npm install [--save] ast-util
```

## API

# callArraySlice(scope, node[, begin, end])

Returns a call to `Array.prototype.slice` with `node` as the context and
`begin` and `end` as the arguments to `slice`.

# callFunctionBind(scope, fn, context[, args])

Returns a call to `Function.prototype.bind` using either `call` or `apply`
depending on what the value of `args` is. If `args` is an expression then
`apply` is used. If `args` is an array of expressions, then `call`.

# callGet(scope, object, property, receiver)

The [[Get]] internal method on objects would look something like
[helpers/get.js](helpers/get.js).

# callGetOwnPropertyDescriptor(scope, object, property)

Returns a call to `Object.getOwnPropertyDescriptor` with the given `object` and
`property`.

# callGetPrototypeOf(scope, object)

Returns a call to `Object.getPrototypeOf` with the given `object`.

# callHasOwnProperty(scope, node, property)

Returns a call to `hasOwnProperty` with `node` as the context and `property` as
the property to check.

# callSharedMethod(scope, callee, args)

Returns a call to the given `callee` with `args` as the arguments. If `callee`
is a string then it is treated as a globally-accessible function such as
`Object.defineProperty` which will be stored in a unique temporary variable.
Subsequent calls to this function will re-use the same temporary variable.

# callSharedMethodWithContext(scope, callee, context, args)

Returns a call to the given `callee` with `context` as the method context and
`args` as the arguments. If `callee` is a string then it is treated as a
globally-accessible function such as `Array.prototype.slice` which will be
stored in a unique temporary variable. Subsequent calls to this function will
re-use the same temporary variable.

# getGlobals(ast)

Gets a list of identifiers referencing global variables anywhere within the
given `ast`. Assuming the ast is for this code:

```js
var a;
function b(){ return c; }
b(d);
```

Then `getGlobals` will return two identifiers, `c` and `d`.

# identifierForString(string)

Generate a safe JavaScript identifier for the given string.

# injectShared(scope, name, expression)

Injects a shared variable with a unique identifier. Only the first call with
the same `scope` and `name` will result in a variable declaration being
created. The `expression` passed in can either be an AST node or a function to
generate one. This function is generally used to inject repeatedly-used values
and prevent repeated execution.

# injectVariable(scope, identifier[, init])

Injects a variable with the given `identifier` into the given `scope` as a
`var` declaration with an optional initial value.

# isReference(path)

Determines whether the given `path` is a value reference. For example, `a` and
`b` are references, but `c` is not:

```js
a(b.c);
```

Only identifiers count as references.

# isUsed(scope, name)

Determines whether the given `name` should be considered "used" in the given
`scope`. For a name to be used, it should either:

  1. Be declared in this scope or a parent scope.
  2. Be referenced in this scope, a parent scope, or any child scopes.

For example, `a`, `b`, and `d` are used in the global scope of this example
while `c` is not:

```js
var a;
function b() {}

try {
  a = b(d);
} catch (c) {
}
```


# sharedFor(scope, name)

Injects a shared variable by getting the named value from a dotted path. For
example, this will return an identifier that can be used in place of the named
expression:

```js
sharedFor(scope, 'Object.defineProperty')
```

Subsequent calls to `sharedFor` in the same scope will return the same
identifier.

# uniqueIdentifier(scope[, name])

Generates an identifier guaranteed not to collide with any others in the given
`scope`. This function will also never generate the same identifier twice for
any `scope` whose global scope already got that identifier.

Called in a scope with no global references and no variables, the first time
this function is called it will return an identifier named `$__0`.

When called with a name that name will be used with a prefix, "$\_\_", if
possible. If that name is already used then it will append incrementing numbers
until it finds a name that isn't used.


## Usage

These methods are useful to source transforms, such as transpilers or macros.
Such transforms often have to insert variables into scopes and replace
expressions. Using `injectVariable` and `injectShared` are specifically for
that purpose. In conjunction with `ast-types`, here's how you'd write a simple
version of a `swap` macro:

```js
// var tmp;
var tmp = util.injectVariable(
  this.scope,
  util.uniqueIdentifier(this.scope)
);

this.replace(
  b.sequenceExpression([
    // tmp = left
    b.assignmentExpression(
      '=',
      tmp,
      left
    ),
    // left = right
    b.assignmentExpression(
      '=',
      left,
      right
    ),
    // right = tmp
    b.assignmentExpression(
      '=',
      right,
      tmp
    )
  ])
);
```

See [examples/swap-macro.js](examples/swap-macro.js) for a more complete
example.

## Contributing

[![Build Status](https://travis-ci.org/eventualbuddha/ast-util.png?branch=master)](https://travis-ci.org/eventualbuddha/ast-util)


### Setup

First, install the development dependencies:

```
$ npm install
```

Then, try running the tests:

```
$ make test
```

If you're adding or editing code that injects helpers into a scope, you'll need
to edit and run the Makefile to have it generate the files in lib/helpers from
the files in helpers.


### Pull Requests

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request


## Acknowledgements

Huge thanks to [Ben Newman][benjamn] for [ast-types][ast-types], on which much
of this library depends.

[benjamn]: https://github.com/benjamn
[ast-types]: https://github.com/benjamn/ast-types
