π A tiny and fast ESTree-compliant AST walker and modifier.
- Works on ESTree-compliant ASTs such as the ones produced by Acorn.
- Out-of-the-box functions such as source code comments insertion for Astring.
- No dependencies and small footprint.
- Now also includes a TypeScript example ;)
Install with the Node Package Manager:
npm install astravel
Alternatively, checkout this repository and install the development dependencies to build the module file:
git clone https://github.com/davidbonnet/astravel.git
cd astravel
npm install
A browser-ready minified version of Astravel is available at dist/astravel.min.js
.
The astravel
module exports the following items:
This object describes a basic AST traveler. It contains the following methods:
go(node, state, opts)
: Travels through the provided ASTnode
with a givenstate
(an object that can be of any type) by recursively calling this method.find(predicate, node, state, opts) β { node, state }?
: Returns{ node, state, opts }
for whichpredicate(node, state, opts)
returns truthy, starting at the specified ASTnode
and with the providedstate
. Otherwise, returnsundefined
.[NodeType](node, state, opts)
: Method handler for a specificNodeType
.makeChild(properties) β traveler
: Returns a custom AST traveler that inherits fromthis
traveler with its own providedproperties
and the propertysuper
that points tothis
traveler.
This function is similar to astravel.defaultTraveler.makeChild
: it returns a traveler that inherits from the defaultTraveler
with its own provided properties
and the property super
that points to the defaultTraveler
object. These properties should redefine the traveler's behavior by implementing the go(node, state, opts)
method and/or any node handler.
When redefining the go
method, make sure its basic functionality is kept by calling the parent's go
method to keep traveling through the AST:
var customTraveler = astravel.makeTraveler({
go: function(node, state, opts) {
// Code before entering the node
console.log('Entering ' + node.type)
// Call the parent's `go` method
this.super.go.call(this, node, state)
// Code after leaving the node
console.log('Leaving ' + node.type)
},
})
To skip specific node types, the most effective way is to replace the corresponding node handlers with a function that does nothing:
var ignore = Function.prototype
var customTraveler = astravel.makeTraveler({
FunctionDeclaration: ignore,
FunctionExpression: ignore,
ArrowFunctionExpression: ignore,
})
This function attaches a list of comments
to the corresponding nodes of a provided ast
and returns that same ast
. The ast
is modified in-place and only the nodes getting comments are augmented with a comments
and/or a trailingComments
array property.
Each comment should be an object with the following properties:
type
:"Line"
or"Block"
value
: Comment string valuestart
: Comment starting character offset numberend
: Comment ending character offset numberloc
: Location object withstart
andend
properties containing one-basedline
number and zero-basedcolumn
number properties.
This example shows how to obtain a proper list of comments
of a given source code
with Acorn and how to attach them on the generated ast
:
var comments = [];
var ast = acorn.parse(code, {
// This ensures that the `loc` property is present on comment objects
locations: true,
// Acorn will store the comment objects in this array
onComment: comments
});
// Attach comments on the ast
astravel.attachComments(ast, comments);
The algorithm assumes that comments are not put in exotic places, such as in-between function arguments, and proceeds as follows:
- For a given statement, it stores all comments right above it and on the same line to it's right side in a
comments
property. - If a comment block is at the beginning of a code block, it is attached to that code block.
- Comments not followed by any statement in a code block are attached as
trailingComments
to that code block.
In this example, the comments tell to which statement they are attached:
// Attached to the variable declaration just below
var point = {
// Attached to the property definition just below
x: 0,
y: 0, // Attached to the property definition on its left
}
/*
Attached to the function declaration just below.
*/
function add(a, b) {
/*
Attached to the function body because it is the first comment block.
*/
return a + b // Attached to the return statement on its left
// Trailing comment attached as such to the function body
}
// Trailing comment attached as such to the program body
All building scripts are defined in the package.json
file and rely on the Node Package Manager. All commands must be run from within the root repository folder.
Production code can be obtained from the dist
folder by running:
npm run build
If you are already using a JavaScript 6 to 5 compiler for your project, or a JavaScript 6 compliant interpreter, you can include the src/astravel.js
file directly.
A minified version of Astravel with source maps can be obtained at dist/astravel.min.js
by running:
npm run build:minified
If you are working on Astring, you can enable Babel's watch mode to automatically transpile to the dist
folder at each update by running:
npm start
While making changes to Astravel, make sure it passes the tests (it checks code formatting and unit tests):
npm test
The examples demonstrate using the parser with both typescript-eslint-parser and acorn
Planned features and releases are outlined on the milestones page.