1.1.0 • Published 6 years ago

astley v1.1.0

Weekly downloads
2
License
MIT
Repository
github
Last release
6 years ago

Astley 🕶️

TravisCI

Easy AST manipulation. Dynamically modify JavaScript code with ease.

Example Usage

You can provide Astley with either a string containing ECMAScript code or an actual JavaScript object. In the latter case, it will do its best to turn it into an AST that can be queried and manipulated.

const Astley = require('astley');

let astley = Astley.from(`
  // just a plain ol' object

  const neverGonnaGiveYouUp = {

  };
`);

// You can traverse the AST by using the search function.

const neverGonnaGiveYouUp = astley.search(obj => obj.type === 'ObjectExpression');

// Let's add a new property.

neverGonnaGiveYouUp.prop('never', { gonna: 'let you down' });

astley.toString();

/** Which returns: **/ 
 
// // just a plain ol' object

// const neverGonnaGiveYouUp = {
//  never: {
//    gonna: "let you down"
//  }
// };


/** Now let's create an AST straight from an object (let's try a function)... **/

astley = Astley.from(function(){

  console.log('never gonna run around');

});

/** ... and modify its contents! **/

const node = astley.search(o  =>  o.type === 'BlockStatement')[0];

node.append("console.log('and desert you');");

astley.toString();

/** Now our code looks like this: **/

// function() {
//   console.log('never gonna run around');
//   console.log('and desert you');
// }


/** But we can also append new code at a chosen index. **/

node.append("console.log('never gonna let you down');\n", 1);

astley.toString();  

// function() {
//   console.log('never gonna run around');
//   console.log('never gonna let you down');
//   console.log('and desert you');
// }

Installation

npm install --save astley

API

Astley

AST

Astley uses recast the generate an AST from ECMAScript code. Astley nodes have a .ast property that will allow you to access the tree directly.

javascript-stringify is used to convert objects into strings containing ECMAScript literals. This is used to convert an object into an AST by first converting the object into code and then passing it to Recast. There's surely a better means of converting objects to ASTs, but this seems to work just fine for my needs.

Search

Searching objects in the AST is done using a simple filter function. It returns all objects that caused the filter function to return a truthy value. This function is really dumb, but I wrote it because I didn't like how complicated other similar solutions were. All I wanted to do was find objects that contain matching properties.

astley.search(obj  =>  obj.type === 'ObjectExpression' && obj.properties.some(x  =>  x.key.name === 'foo'));

By default, errors will not be raised from inside the filter function. To allow errors to be thrown, pass the following configuration:

astley.search({ throwErrors:  true }, obj  =>  obj.type === 'ObjectExpression');

Append/Prepend

Appending and prepending works a lot like jQuery if you have a node with a body.

astley.append('{placed: "on bottom"}');

The append() method will convert the string or object to an AST node and add it to the bottom of the body of the current node. If the current node has no body, it will simply return false and not append anything.

Prepending works the same, but places items at the top of the body.

astley.prepend('{goes: "on top"}');

But what if you want to append a string literal without wrapping it in a string? If you must do that, you can use appendString() and prependString() respectively.

Both the append() and prepend() methods support inserting at a specific position. If you want to insert an item at a specific point in the body of a node, you can pass an index. Any items inserted will be inserted at that index and the item already at that index will be pushed ahead to make room.

astley.append('"put me somewhere";', 5);

Properties

If a node has a properties object, you can modify those properties with the prop() method:

ast.prop('rules', "You know them.");
ast.toString();
// {
//    rules: "You know them."
// }

The props() method will write multiple properties from an object.

astley.props({
  we: "have known",
  eachOther: "for so long"
});

The removeProp() method will remove the property with the given name.

Any of the property methods will return false if the input can't be written to the node(i.e. the node does not have properties).

Testing

Tests use Mocha w/ Chai assertions. Install Mocha globally and run mocha.

Contribute

This project is definitely not feature-complete. If you would like to contribute, please create an issue or a pull-request. Any work contributed should also include tests.

License

See LICENSE.txt.