1.7.3 • Published 8 months ago

estree-toolkit v1.7.3

Weekly downloads
16
License
MIT
Repository
github
Last release
8 months ago

Installation

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

Usage

// Supports both CommonJS and ES Modules
// ES Module
import { traverse, builders as b } from 'estree-toolkit';
// CommonJS
const { traverse, builders: b } = require('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 has 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.scope.hasGlobalBinding('require') // => true
  }
});

Renaming a binding

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

const ast = parseModule(`
const a = 0

a.reload()
while (a.ok) a.run()
`);

traverse(ast, {
  $: { scope: true },
  Program(path) {
    // `a` -> `b`
    path.scope.renameBinding('a', 'b')
  }
});

// Output code:
// const b = 0
//
// b.reload()
// while (b.ok) b.run()

Utilities

There are several static utilities that you can use.

  • evaluate\ Evaluates the given path.

    const { utils: u, traverse } = 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
      }
    });
    
    traverse(parseModule(`
      ({
        text: 'This is an object',
        data: [1, 'two']
      })
    `), {
      ObjectExpression(path) {
        u.evaluate(path) // => { value: { text: 'This is an object', data: [1, 'two'] } }
      }
    });
    
    traverse(parseModule(`1 > 5 ? 'YES' : 'NO'`), {
      ConditionalExpression(path) {
        u.evaluate(path) // => { value: 'NO' }
      }
    });
  • evaluateTruthy\ Evaluates the path for truthiness and returns true, false or undefined depending on evaluation result.

There's more functionalities, please read the documentation.

Documentation

You can find the documentation at https://estree-toolkit.netlify.app/

Why another traverser?

I know there is Babel. But there are other tools which are faster than Babel. For example, meriyah is 3x faster than @babel/parser, astring is up to 50x faster than @babel/generator. But these tool only work with ESTree AST. I wanted to use these faster alternatives for one of my projects but could not find any traverser with batteries-included. So I built one myself, with awesome scope analysis, it has all the things that you would need for traversing an ESTree AST. Also, a little bit faster than Babel.

License

Licensed under the MIT License.

1.7.3

8 months ago

1.7.2

9 months ago

1.7.1

9 months ago

1.7.0

9 months ago

1.6.3

11 months ago

1.6.2

11 months ago

1.6.1

1 year ago

1.6.0

1 year ago

1.5.0

1 year ago

1.4.0

1 year ago

1.2.7

2 years ago

1.3.1

2 years ago

1.3.0

2 years ago

1.2.6

3 years ago

1.2.5

3 years ago

1.2.4

3 years ago

1.2.3

3 years ago

1.2.2

3 years ago

1.2.0

3 years ago

1.2.1

3 years ago

1.1.0

3 years ago

1.0.9

3 years ago

1.0.8

3 years ago

1.0.7

3 years ago

1.0.6

3 years ago

1.0.5

3 years ago

1.0.4

3 years ago

1.0.3

3 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago