# babylon-walk

> Lightweight Babylon AST traversal

Latest version **1.0.2** (published 2016-09-11) · MIT license · 0 weekly downloads

## Install

```sh
npm install babylon-walk
pnpm add babylon-walk
yarn add babylon-walk
bun add babylon-walk
```

## Health

**Score 18/100 (F)** — status: abandoned.

Positive: has types package; no vulnerabilities.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.2 |
| Published | 2016-09-11 |
| First published | 2016-09-11 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | separate (@types/babylon-walk) |
| Module format | CommonJS |
| Dependencies | 3 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 44 |
| Author | Timothy Gu |
| Maintainers | timothygu |

## Links

- npm: https://www.npmjs.com/package/babylon-walk
- Repository: https://github.com/pugjs/babylon-walk
- Homepage: https://github.com/pugjs/babylon-walk#readme
- Issues: https://github.com/pugjs/babylon-walk/issues
- npm.io page: https://npm.io/package/babylon-walk

## Dependencies (3)

- [babel-types](https://npm.io/package/babel-types.md) ^6.15.0
- [lodash.clone](https://npm.io/package/lodash.clone.md) ^4.5.0
- [babel-runtime](https://npm.io/package/babel-runtime.md) ^6.11.6

## Recent versions

- 1.0.2 (latest) — 2016-09-11
- 1.0.1 — 2016-09-11
- 1.0.0 — 2016-09-11

## README

# babylon-walk

Lightweight AST traversal tools for [Babylon] ASTs.

Babylon is the parser used by the [Babel] project, which supplies the wonderful [babel-traverse] module for walking Babylon ASTs. Problem is, babel-traverse is very heavyweight, as it is designed to supply utilities to make all sorts of AST transformations possible. For simple AST walking without transformation, babel-traverse brings a lot of overhead.

This module loosely implements the API of Acorn parser's [walk module], which is a lightweight AST walker for the ESTree AST format.

In my tests, babylon-walk's ancestor walker (the most complex walker provided by this module) is about 8 times faster than babel-traverse, if the visitors are cached and the same AST is used for all runs. It is about 16 times faster if a fresh AST is used every run.

[![Dependency Status](https://img.shields.io/david/pugjs/babylon-walk.svg)](https://david-dm.org/pugjs/babylon-walk)
[![NPM version](https://img.shields.io/npm/v/babylon-walk.svg)](https://www.npmjs.com/package/babylon-walk)

[Babylon]: https://github.com/babel/babylon
[Babel]: https://babeljs.io/
[babel-traverse]: https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-babel-traverse
[walk module]: https://github.com/ternjs/acorn#distwalkjs

## Installation

```sh
$ npm install babylon-walk
```

## API

```js
var walk = require('babylon-walk');
```

### walk.simple(node, visitors, state)

Do a simple walk over the AST. `node` should be the AST node to walk, and `visitors` an object containing Babel [visitors]. Each visitor function will be called as `(node, state)`, where `node` is the AST node, and `state` is the same `state` passed to `walk.simple`.

When `walk.simple` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to [cache your visitors] and communicate state leveraging the `state` parameter. (One difference between the linked article and babylon-walk is that the state is only accessible through the `state` variable, never as `this`.)

All [babel-types] aliases (e.g. `Expression`) and the union syntax (e.g. `'Identifier|AssignmentPattern'(node, state) {}`) work.

### walk.ancestor(node, visitors, state)

Do a simple walk over the AST, but memoizing the ancestors of the node and making them available to the visitors. `node` should be the AST node to walk, and `visitors` an object containing Babel [visitors]. Each visitor function will be called as `(node, state, ancestors)`, where `node` is the AST node, `state` is the same `state` passed to `walk.ancestor`, and `ancestors` is an array of ancestors to the node (with the outermost node being `[0]` and the current node being `[ancestors.length - 1]`). If `state` is not specified in the call to `walk.ancestor`, the `state` parameter will be set to `ancestors`.

When `walk.ancestor` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to [cache your visitors] and communicate state leveraging the `state` parameter. (One difference between the linked article and babylon-walk is that the state is only accessible through the `state` variable, never as `this`.)

All [babel-types] aliases (e.g. `Expression`) and the union syntax (e.g. `'Identifier|AssignmentPattern'(node, state) {}`) work.

### walk.recursive(node, visitors, state)

Do a recursive walk over the AST, where the visitors are responsible for continuing the walk on the child nodes of their target node. `node` should be the AST node to walk, and `visitors` an object containing Babel [visitors]. Each visitor function will be called as `(node, state, c)`, where `node` is the AST node, `state` is the same `state` passed to `walk.recursive`, and `c` is a function that takes a single node as argument and continues walking _that_ node. If no visitor for a node is provided, the default walker algorithm will still be used.

When `walk.recursive` is called with a fresh set of visitors, it will first "explode" the visitors (e.g. expanding `Visitor(node, state) {}` to `Visitor() { enter(node, state) {} }`). This exploding process can take some time, so it is recommended to [cache your visitors] and communicate state leveraging the `state` parameter. (One difference between the linked article and babylon-walk is that the state is only accessible through the `state` variable, never as `this`.)

Unlike other babylon-walk walkers, `walk.recursive` does not call the `exit` visitor, only the `enter` (the default) visitor, of a specific node type.

All [babel-types] aliases (e.g. `Expression`) and the union syntax (e.g. `'Identifier|AssignmentPattern'(node, state) {}`) work.

In the following example, we are trying to count the number of functions in the outermost scope. This means, that we can simply walk all the statements and increment a counter if it is a function declaration or expression, and then stop walking. Note that we do not specify a visitor for the `Program` node, and the default algorithm for walking `Program` nodes is used (which is what we want). Also of note is how I bring the `visitors` object outside of `countFunctions` so that the object can be cached to improve performance.

```js
import * as t from 'babel-types';
import {parse} from 'babylon';

const visitors = {
  Statement(node, state, c) {
    if (t.isVariableDeclaration(node)) {
      for (let declarator of node.declarations) {
        // Continue walking the declarator
        c(declarator);
      }
    } else if (t.isFunctionDeclaration(node)) {
      state.counter++;
    }
  },

  VariableDeclarator(node, state) {
    if (t.isFunction(node.init)) {
      state.counter++;
    }
  }
};

function countFunctions(node) {
  const state = {
    counter: 0
  };
  walk.recursive(node, visitors, state);
  return state.counter;
}

const ast = parse(`
  // Counts
  var a = () => {};

  // Counts
  function b() {
    // Doesn't count
    function c() {
    }
  }

  // Counts
  const c = function d() {};
`);

countFunctions(ast);
// = 3
```

[babel-types]: https://github.com/babel/babel/tree/master/packages/babel-types
[cache your visitors]: https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-optimizing-nested-visitors
[visitors]: https://github.com/thejameskyle/babel-handbook/blob/master/translations/en/plugin-handbook.md#toc-visitors

## Caveat

For those of you migrating from Acorn to Babylon, there are a few things to be aware of.

1. The visitor caching suggestions do not apply to Acorn's walk module, but do for babylon-walk.

2. babylon-walk does not provide any of the other functions Acorn's walk module provides (e.g. `make`, `findNode*`).

3. babylon-walk does not use a `base` variable. The walker algorithm is the same as what babel-traverse uses.
   - That means certain nodes that are not walked by Acorn, such as the `property` property of a non-computed `MemberExpression`, are walked by babylon-walk.

## License

  MIT

---
_Source: https://npm.io/package/babylon-walk · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
