JSPM

  • Created
  • Published
  • Downloads 62799
  • Score
    100M100P100Q158072F
  • License MIT

Traverser, scope tracker, and more tools for working with ESTree AST

Package Exports

  • estree-toolkit
  • estree-toolkit/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (estree-toolkit) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

estree-toolkit

Tools for working with ESTree AST

npm Circle CI codecov License

Installation

npm i estree-toolkit
# or
yarn add estree-toolkit

Basic operations

Traversing an AST

const { traverse } = require('estree-toolkit');

traverse(ast, {
  Program(path) {
    // Do something with the path
  }
});

Building Nodes

const { builders: b } = require('estree-toolkit');

b.identifier('x'); // => { type: 'Identifier', name: 'x' }

Checking node types

const { traverse, is } = require('estree-toolkit');
const { parseModule } = require('meriyah');

const ast = parseModule(`x = 0`);

traverse(ast, {
  AssignmentExpression(path) {
    if (is.identifier(path.node.left, { name: 'x' })) {
      // `left` is an identifier with name `x`
    }
  }
});

Replacing a node

const { traverse, builders: b } = require('estree-toolkit');
const { parseModule } = require('meriyah');

const ast = parseModule('a = b');

traverse(ast, {
  Identifier(path) {
    if (path.node.name === 'a') {
      path.replaceWith(b.identifier('c'));
    }
  }
});

// Now the AST represents - `c = b`

Collecting scope information

const { traverse } = require('estree-toolkit');

traverse(ast, {
  // Enable scope
  $: { scope: true },
  Program(path) {
    // `path.scope` is now available in all paths
  }
});

Checking if a binding is available

const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');

const ast = parseModule(`
import { a } from 'source';

const { b, c: [d, { e }] } = a;
`);

traverse(ast, {
  $: { scope: true },
  Program(path) {
    path.scope.hasBinding('a') // => true
    path.scope.hasBinding('b') // => true
    path.scope.hasBinding('c') // => false
    path.scope.hasBinding('d') // => true
    path.scope.hasBinding('e') // => true
  }
});

Getting all references of a binding

const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');

const ast = parseModule(`
import { a } from 'source';

fn(a);
s = a;
let obj = { a };
`);

traverse(ast, {
  $: { scope: true },
  Program(path) {
    // Returns all the paths that reference the binding `a`
    path.scope.getBinding('a').references // => [NodePath, NodePath, NodePath]
  }
});

Checking if a global have been used

const { traverse } = require('estree-toolkit');
const { parseModule } = require('meriyah');

const ast = parseModule(`
const fx = require('fx-mod');
`);

traverse(ast, {
  $: { scope: true },
  Program(path) {
    path.hasGlobalBinding('require') // => true
  }
});

Utilities

There are several static utilities that you can use.

  • evaluate
    Evaluates the given path. For now it only supports evaluation of logical, binary and unary operations.
    const { utils: u } = require('estree-toolkit');
    // We are using `meriyah` but you can use any parser (like `acorn`)
    const { parseModule } = require('meriyah');
    
    traverse(parseModule(`1 + 2`), {
      BinaryExpression(path) {
        u.evaluate(path) // => { value: 3 }
      }
    });
    
    traverse(parseModule(`1 === 2`), {
      BinaryExpression(path) {
        u.evaluate(path) // => { value: false }
      }
    });
    
    traverse(parseModule(`iDoNotKnowWhatThisIs === 55`), {
      BinaryExpression(path) {
        u.evaluate(path) // => undefined
      }
    });
  • evaluateTruthy
    Evaluates the path for truthiness and returns true, false or undefined depending on evaluation result.
  • hasBinding
    Checks if any binding with the name is available in the containing scope.
    const { utils: u } = require('estree-toolkit');
    const { parseModule } = require('meriyah');
    
    const ast = parseModule(`
      {
        let a;
        {
          id1;
        }
      }
    
      id2;
    `);
    
    traverse(ast, {
      Identifier(path) {
        if (path.node.name === 'id1') {
          u.hasBinding(path, 'a') // => true
        } else if (path.node.name === 'id2') {
          u.hasBinding(path, 'a') // => false
        }
      }
    });

Documentation

The documentation is work in progress. You can find the documentation at https://estree-toolkit.netlify.app/

License

Licensed under the MIT License.