Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
acorn-walk
Advanced tools
The acorn-walk package is a syntax tree walker for the abstract syntax trees (ASTs) that Acorn produces. It allows developers to easily traverse and manipulate JavaScript code structures represented as ASTs. This is useful for tasks such as static analysis, code transformation, and optimization.
Simple tree walking
This feature allows you to perform a simple walk over the AST nodes and apply specific functions to nodes of a particular type. In the code sample, `walk.simple` is used to log all literals in the parsed code.
const acorn = require('acorn');
const walk = require('acorn-walk');
const ast = acorn.parse('let x = 10;', {ecmaVersion: 2020});
walk.simple(ast, {
Literal(node) {
console.log(`Found a literal: ${node.value}`);
}
});
Full tree walking
This feature allows you to visit every node in the AST, regardless of its type. The code sample demonstrates using `walk.full` to log the type of every node in the AST.
const acorn = require('acorn');
const walk = require('acorn-walk');
const ast = acorn.parse('let x = 10;', {ecmaVersion: 2020});
walk.full(ast, node => {
console.log(`Type of node: ${node.type}`);
});
Ancestor tree walking
This feature allows you to walk the AST like `walk.simple`, but it also provides an array of ancestor nodes to each callback. The code sample logs each literal found and its ancestors.
const acorn = require('acorn');
const walk = require('acorn-walk');
const ast = acorn.parse('let x = 10;', {ecmaVersion: 2020});
walk.ancestor(ast, {
Literal(node, ancestors) {
console.log(`Found a literal with value ${node.value} and ancestors ${ancestors.map(a => a.type).join(', ')}`);
}
});
Estraverse is an ECMAScript JS AST traversal functions library. It provides similar functionality to acorn-walk, allowing for traversal and manipulation of ASTs. Estraverse is not tied to a specific parser, making it more flexible if you're working with different AST formats.
Babel-traverse is part of the Babel toolchain and is used for traversing and manipulating the Babel-generated ASTs. It is more powerful and complex than acorn-walk, with a focus on transforming ES6+ code, and it integrates well with the Babel ecosystem.
Recast provides AST traversal and manipulation capabilities, with a focus on preserving the original formatting of the code as much as possible. It differs from acorn-walk in that it includes its own parser and printer, and it's designed to make the AST editing process less intrusive on code style.
An abstract syntax tree walker for the ESTree format.
Acorn is open source software released under an MIT license.
You are welcome to report bugs or create pull requests on github.
The easiest way to install acorn is from npm
:
npm install acorn-walk
Alternately, you can download the source and build acorn yourself:
git clone https://github.com/acornjs/acorn.git
cd acorn
npm install
An algorithm for recursing through a syntax tree is stored as an object, with a property for each tree node type holding a function that will recurse through such a node. There are several ways to run such a walker.
simple(node, visitors, base, state)
does a 'simple' walk over a
tree. node
should be the AST node to walk, and visitors
an object
with properties whose names correspond to node types in the ESTree
spec. The properties should contain
functions that will be called with the node object and, if applicable
the state at that point. The last two arguments are optional. base
is a walker algorithm, and state
is a start state. The default
walker will simply visit all statements and expressions and not
produce a meaningful state. (An example of a use of state is to track
scope at each point in the tree.)
const acorn = require("acorn")
const walk = require("acorn-walk")
walk.simple(acorn.parse("let x = 10"), {
Literal(node) {
console.log(`Found a literal: ${node.value}`)
}
})
ancestor(node, visitors, base, state)
does a 'simple' walk over
a tree, building up an array of ancestor nodes (including the current node)
and passing the array to the callbacks as a third parameter.
const acorn = require("acorn")
const walk = require("acorn-walk")
walk.ancestor(acorn.parse("foo('hi')"), {
Literal(_node, _state, ancestors) {
console.log("This literal's ancestors are:", ancestors.map(n => n.type))
}
})
recursive(node, state, functions, base)
does a 'recursive'
walk, where the walker functions are responsible for continuing the
walk on the child nodes of their target node. state
is the start
state, and functions
should contain an object that maps node types
to walker functions. Such functions are called with (node, state, c)
arguments, and can cause the walk to continue on a sub-node by calling
the c
argument on it with (node, state)
arguments. The optional
base
argument provides the fallback walker functions for node types
that aren't handled in the functions
object. If not given, the
default walkers will be used.
make(functions, base)
builds a new walker object by using the
walker functions in functions
and filling in the missing ones by
taking defaults from base
.
full(node, callback, base, state)
does a 'full' walk over a
tree, calling the callback with the arguments (node, state, type) for
each node
fullAncestor(node, callback, base, state)
does a 'full' walk
over a tree, building up an array of ancestor nodes (including the
current node) and passing the array to the callbacks as a third
parameter.
const acorn = require("acorn")
const walk = require("acorn-walk")
walk.full(acorn.parse("1 + 1"), node => {
console.log(`There's a ${node.type} node at ${node.ch}`)
})
findNodeAt(node, start, end, test, base, state)
tries to locate
a node in a tree at the given start and/or end offsets, which
satisfies the predicate test
. start
and end
can be either null
(as wildcard) or a number. test
may be a string (indicating a node
type) or a function that takes (nodeType, node)
arguments and
returns a boolean indicating whether this node is interesting. base
and state
are optional, and can be used to specify a custom walker.
Nodes are tested from inner to outer, so if two nodes match the
boundaries, the inner one will be preferred.
findNodeAround(node, pos, test, base, state)
is a lot like
findNodeAt
, but will match any node that exists 'around' (spanning)
the given position.
findNodeAfter(node, pos, test, base, state)
is similar to
findNodeAround
, but will match all nodes after the given position
(testing outer nodes before inner nodes).
FAQs
ECMAScript (ESTree) AST walker
The npm package acorn-walk receives a total of 37,357,245 weekly downloads. As such, acorn-walk popularity was classified as popular.
We found that acorn-walk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.